This commit is contained in:
Janus C. H. Knudsen 2025-10-02 23:11:26 +02:00
parent 88702e574a
commit 89e8a3f7b2
6 changed files with 137 additions and 198 deletions

View file

@ -3,7 +3,7 @@
import { CalendarMode } from '../types/CalendarTypes'; import { CalendarMode } from '../types/CalendarTypes';
import { HeaderRenderer, DateHeaderRenderer, ResourceHeaderRenderer } from '../renderers/HeaderRenderer'; import { HeaderRenderer, DateHeaderRenderer, ResourceHeaderRenderer } from '../renderers/HeaderRenderer';
import { ColumnRenderer, DateColumnRenderer, ResourceColumnRenderer } from '../renderers/ColumnRenderer'; import { ColumnRenderer, DateColumnRenderer, ResourceColumnRenderer } from '../renderers/ColumnRenderer';
import { EventRendererStrategy, DateEventRenderer, ResourceEventRenderer } from '../renderers/EventRenderer'; import { EventRendererStrategy, DateEventRenderer } from '../renderers/EventRenderer';
import { calendarConfig } from '../core/CalendarConfig'; import { calendarConfig } from '../core/CalendarConfig';
/** /**
@ -37,11 +37,11 @@ export class CalendarTypeFactory {
eventRenderer: new DateEventRenderer() eventRenderer: new DateEventRenderer()
}); });
this.registerRenderers('resource', { //this.registerRenderers('resource', {
headerRenderer: new ResourceHeaderRenderer(), // headerRenderer: new ResourceHeaderRenderer(),
columnRenderer: new ResourceColumnRenderer(), // columnRenderer: new ResourceColumnRenderer(),
eventRenderer: new ResourceEventRenderer() // eventRenderer: new ResourceEventRenderer()
}); //});
this.isInitialized = true; this.isInitialized = true;
} }

View file

@ -44,11 +44,7 @@ export class AllDayManager {
this.allDayEventRenderer = new AllDayEventRenderer(); this.allDayEventRenderer = new AllDayEventRenderer();
// Sync CSS variable with TypeScript constant to ensure consistency // Sync CSS variable with TypeScript constant to ensure consistency
document.documentElement.style.setProperty( document.documentElement.style.setProperty('--single-row-height', `${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`);
'--single-row-height',
`${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`
);
this.setupEventListeners(); this.setupEventListeners();
} }
@ -59,6 +55,9 @@ export class AllDayManager {
eventBus.on('drag:mouseenter-header', (event) => { eventBus.on('drag:mouseenter-header', (event) => {
const payload = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail; const payload = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail;
if (payload.draggedClone.hasAttribute('data-allday'))
return;
console.log('🔄 AllDayManager: Received drag:mouseenter-header', { console.log('🔄 AllDayManager: Received drag:mouseenter-header', {
targetDate: payload.targetColumn, targetDate: payload.targetColumn,
originalElementId: payload.originalElement?.dataset?.eventId, originalElementId: payload.originalElement?.dataset?.eventId,
@ -75,33 +74,27 @@ export class AllDayManager {
originalElementId: originalElement?.dataset?.eventId originalElementId: originalElement?.dataset?.eventId
}); });
//this.checkAndAnimateAllDayHeight();
}); });
// 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, draggedClone, mouseOffset } = (event as CustomEvent<DragStartEventPayload>).detail; let payload: DragStartEventPayload = (event as CustomEvent<DragStartEventPayload>).detail;
// Check if this is an all-day event by checking if it's in all-day container if (!payload.draggedClone?.hasAttribute('data-allday')) {
const isAllDayEvent = draggedElement.closest('swp-allday-container'); return;
if (!isAllDayEvent) return; // Not an all-day event }
const eventId = draggedElement.dataset.eventId; this.allDayEventRenderer.handleDragStart(payload);
console.log('🎯 AllDayManager: Starting drag for all-day event', { eventId });
this.handleDragStart(draggedElement, eventId || '', mouseOffset);
}); });
eventBus.on('drag:column-change', (event) => { eventBus.on('drag:column-change', (event) => {
const { originalElement: draggedElement, draggedClone, mousePosition } = (event as CustomEvent<DragColumnChangeEventPayload>).detail; let payload: DragColumnChangeEventPayload = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
if (draggedClone == null) if (!payload.draggedClone?.hasAttribute('data-allday')) {
return; return;
if (!draggedClone.hasAttribute('data-allday')) {
return; // This is not an all-day event
} }
this.handleColumnChange(draggedClone, mousePosition); this.handleColumnChange(payload);
}); });
eventBus.on('drag:end', (event) => { eventBus.on('drag:end', (event) => {
@ -320,25 +313,13 @@ export class AllDayManager {
*/ */
private handleConvertToAllDay(payload: DragMouseEnterHeaderEventPayload): void { private handleConvertToAllDay(payload: DragMouseEnterHeaderEventPayload): void {
if (payload.draggedClone?.dataset == null)
console.error("payload.cloneElement.dataset.eventId is null");
console.log('🔄 AllDayManager: Converting to all-day (row 1 only during drag)', {
eventId: payload.draggedClone.dataset.eventId,
targetDate: payload.targetColumn
});
// Get all-day container, request creation if needed
let allDayContainer = this.getAllDayContainer(); let allDayContainer = this.getAllDayContainer();
payload.draggedClone.removeAttribute('style'); payload.draggedClone.removeAttribute('style');
payload.draggedClone.style.gridRow = '1'; payload.draggedClone.style.gridRow = '1';
payload.draggedClone.style.gridColumn = payload.targetColumn.index.toString(); payload.draggedClone.style.gridColumn = payload.targetColumn.index.toString();
payload.draggedClone.dataset.allday = 'true'; // Set the all-day attribute for filtering payload.draggedClone.dataset.allday = 'true';
// Add to container
allDayContainer?.appendChild(payload.draggedClone); allDayContainer?.appendChild(payload.draggedClone);
ColumnDetectionUtils.updateColumnBoundsCache(); ColumnDetectionUtils.updateColumnBoundsCache();
@ -346,63 +327,36 @@ export class AllDayManager {
} }
/**
* Handle drag start for all-day events
*/
private handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset): void {
// Create clone
const clone = originalElement.cloneNode(true) as HTMLElement;
clone.dataset.eventId = `clone-${eventId}`;
// Get container
const container = this.getAllDayContainer();
if (!container) return;
// Add clone to container
container.appendChild(clone);
// Copy positioning from original
clone.style.gridColumn = originalElement.style.gridColumn;
clone.style.gridRow = originalElement.style.gridRow;
// Add dragging style
clone.classList.add('dragging');
clone.style.zIndex = '1000';
clone.style.cursor = 'grabbing';
// Make original semi-transparent
originalElement.style.opacity = '0.3';
console.log('✅ AllDayManager: Created drag clone for all-day event', {
eventId,
cloneId: clone.dataset.eventId,
gridColumn: clone.style.gridColumn,
gridRow: clone.style.gridRow
});
}
/** /**
* Handle drag move for all-day events - SPECIALIZED FOR ALL-DAY CONTAINER * Handle drag move for all-day events - SPECIALIZED FOR ALL-DAY CONTAINER
*/ */
private handleColumnChange(dragClone: HTMLElement, mousePosition: MousePosition): void { private handleColumnChange(dragColumnChangeEventPayload: DragColumnChangeEventPayload): void {
// Get the all-day container to understand its grid structure
const allDayContainer = this.getAllDayContainer(); let allDayContainer = this.getAllDayContainer();
if (!allDayContainer) return; if (!allDayContainer) return;
// Calculate target column using ColumnDetectionUtils let targetColumn = ColumnDetectionUtils.getColumnBounds(dragColumnChangeEventPayload.mousePosition);
const targetColumn = ColumnDetectionUtils.getColumnBounds(mousePosition);
if (targetColumn == null) if (targetColumn == null)
return; return;
if (!dragColumnChangeEventPayload.draggedClone)
return;
// Update clone position - ALWAYS keep in row 1 during drag // Update clone position - ALWAYS keep in row 1 during drag
// Use simple grid positioning that matches all-day container structure // Use simple grid positioning that matches all-day container structure
dragClone.style.gridColumn = targetColumn.index.toString(); dragColumnChangeEventPayload.draggedClone.style.gridColumn = targetColumn.index.toString();
//dragClone.style.gridRow = '1'; // Force row 1 during drag //dragColumnChangeEventPayload.draggedClone.style.gridRow = dragColumnChangeEventPayload.draggedClone.style.gridRow; // Bevar nuværende row
dragClone.style.gridArea = `1 / ${targetColumn.index} / 2 / ${targetColumn.index + 1}`;
} }
private fadeOutAndRemove(element: HTMLElement): void {
element.style.transition = 'opacity 0.3s ease-out';
element.style.opacity = '0';
setTimeout(() => {
element.remove();
}, 300);
}
/** /**
* Handle drag end for all-day events - WITH DIFFERENTIAL UPDATES * Handle drag end for all-day events - WITH DIFFERENTIAL UPDATES
*/ */
@ -414,6 +368,7 @@ export class AllDayManager {
// 2. Normalize clone ID // 2. Normalize clone ID
dragEndEvent.draggedClone.dataset.eventId = dragEndEvent.draggedClone.dataset.eventId?.replace('clone-', ''); dragEndEvent.draggedClone.dataset.eventId = dragEndEvent.draggedClone.dataset.eventId?.replace('clone-', '');
// 3. Create temporary array with existing events + the dropped event // 3. Create temporary array with existing events + the dropped event
let eventId = dragEndEvent.draggedClone.dataset.eventId; let eventId = dragEndEvent.draggedClone.dataset.eventId;
let eventDate = dragEndEvent.finalPosition.column?.date; let eventDate = dragEndEvent.finalPosition.column?.date;
@ -423,6 +378,7 @@ export class AllDayManager {
return; return;
const droppedEvent: CalendarEvent = { const droppedEvent: CalendarEvent = {
id: eventId, id: eventId,
title: dragEndEvent.draggedClone.dataset.title || '', title: dragEndEvent.draggedClone.dataset.title || '',
@ -434,27 +390,29 @@ export class AllDayManager {
}; };
// Use current events + dropped event for calculation // Use current events + dropped event for calculation
const tempEvents = [...this.currentAllDayEvents, droppedEvent]; const tempEvents = [...this.currentAllDayEvents, droppedEvent].except(dragEndEvent.originalElement);
// 4. Calculate new layouts for ALL events // 4. Calculate new layouts for ALL events
this.newLayouts = this.calculateAllDayEventsLayout(tempEvents, this.currentWeekDates); this.newLayouts = this.calculateAllDayEventsLayout(tempEvents, this.currentWeekDates);
// 5. Apply differential updates - only update events that changed // 5. Apply differential updates - only update events that changed
let changedCount = 0; let changedCount = 0;
let container = this.getAllDayContainer();
this.newLayouts.forEach((layout) => { this.newLayouts.forEach((layout) => {
// Find current layout for this event // Find current layout for this event
let currentLayout = this.currentLayouts.find(old => old.calenderEvent.id === layout.calenderEvent.id); let currentLayout = this.currentLayouts.find(old => old.calenderEvent.id === layout.calenderEvent.id);
if (currentLayout?.gridArea !== layout.gridArea) { if (currentLayout?.gridArea !== layout.gridArea) {
changedCount++; changedCount++;
const element = dragEndEvent.draggedClone; let element = container?.querySelector(`[data-event-id="${layout.calenderEvent.id}"]`) as HTMLElement;
if (element) { if (element) {
// Add transition class for smooth animation
element.classList.add('transitioning'); element.classList.add('transitioning');
element.style.gridArea = layout.gridArea; element.style.gridArea = layout.gridArea;
element.style.gridRow = layout.row.toString(); element.style.gridRow = layout.row.toString();
element.style.gridColumn = `${layout.startColumn} / ${layout.endColumn + 1}`; element.style.gridColumn = `${layout.startColumn} / ${layout.endColumn + 1}`;
if (layout.row > ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS) if (layout.row > ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS)
if (!this.isExpanded) if (!this.isExpanded)
element.classList.add('max-event-overflow-hide'); element.classList.add('max-event-overflow-hide');
@ -477,7 +435,8 @@ export class AllDayManager {
dragEndEvent.draggedClone.style.opacity = ''; dragEndEvent.draggedClone.style.opacity = '';
// 7. Restore original element opacity // 7. Restore original element opacity
dragEndEvent.originalElement.remove(); //TODO: this should be an event that only fade and remove if confirmed dragdrop //dragEndEvent.originalElement.remove(); //TODO: this should be an event that only fade and remove if confirmed dragdrop
this.fadeOutAndRemove(dragEndEvent.originalElement);
// 8. Check if height adjustment is needed // 8. Check if height adjustment is needed
this.checkAndAnimateAllDayHeight(); this.checkAndAnimateAllDayHeight();

View file

@ -211,31 +211,32 @@ export class DragDropManager {
// Continue with normal drag behavior only if drag has started // Continue with normal drag behavior only if drag has started
if (this.isDragStarted && this.draggedElement && this.draggedClone) { if (this.isDragStarted && this.draggedElement && this.draggedClone) {
const deltaY = Math.abs(currentPosition.y - this.lastLoggedPosition.y); if (!this.draggedElement.hasAttribute("data-allday")) {
const deltaY = Math.abs(currentPosition.y - this.lastLoggedPosition.y);
// Check for snap interval vertical movement (normal drag behavior) // Check for snap interval vertical movement (normal drag behavior)
if (deltaY >= this.snapDistancePx) { if (deltaY >= this.snapDistancePx) {
this.lastLoggedPosition = currentPosition; this.lastLoggedPosition = currentPosition;
// Consolidated position calculations with snapping for normal drag // Consolidated position calculations with snapping for normal drag
const positionData = this.calculateDragPosition(currentPosition); const positionData = this.calculateDragPosition(currentPosition);
// Emit drag move event with snapped position (normal behavior) // Emit drag move event with snapped position (normal behavior)
const dragMovePayload: DragMoveEventPayload = { const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement, draggedElement: this.draggedElement,
draggedClone: this.draggedClone, draggedClone: this.draggedClone,
mousePosition: currentPosition, mousePosition: currentPosition,
snappedY: positionData.snappedY, snappedY: positionData.snappedY,
columnBounds: positionData.column, columnBounds: positionData.column,
mouseOffset: this.mouseOffset mouseOffset: this.mouseOffset
}; };
this.eventBus.emit('drag:move', dragMovePayload); this.eventBus.emit('drag:move', dragMovePayload);
}
// Check for auto-scroll
this.checkAutoScroll(currentPosition);
} }
// Check for auto-scroll
this.checkAutoScroll(currentPosition);
// Check for column change using cached data
const newColumn = ColumnDetectionUtils.getColumnBounds(currentPosition); const newColumn = ColumnDetectionUtils.getColumnBounds(currentPosition);
if (newColumn == null) if (newColumn == null)
return; return;

View file

@ -3,21 +3,20 @@ import { SwpAllDayEventElement } from '../elements/SwpEventElement';
import { EventLayout } from '../utils/AllDayLayoutEngine'; import { EventLayout } from '../utils/AllDayLayoutEngine';
import { ColumnBounds } from '../utils/ColumnDetectionUtils'; import { ColumnBounds } from '../utils/ColumnDetectionUtils';
import { EventManager } from '../managers/EventManager'; import { EventManager } from '../managers/EventManager';
/** import { DragStartEventPayload } from '../types/EventTypes';
* AllDayEventRenderer - Simple rendering of all-day events import { EventRendererStrategy } from './EventRenderer';
* Handles adding and removing all-day events from the header container
* NOTE: Layout calculation is now handled by AllDayManager
*/
export class AllDayEventRenderer { export class AllDayEventRenderer {
private container: HTMLElement | null = null; private container: HTMLElement | null = null;
private originalEvent: HTMLElement | null = null;
private draggedClone: HTMLElement | null = null;
constructor() { constructor() {
this.getContainer(); this.getContainer();
} }
/**
* Get or cache all-day container, create if it doesn't exist - SIMPLIFIED (no ghost columns)
*/
private getContainer(): HTMLElement | null { private getContainer(): HTMLElement | null {
const header = document.querySelector('swp-calendar-header'); const header = document.querySelector('swp-calendar-header');
@ -27,14 +26,45 @@ export class AllDayEventRenderer {
if (!this.container) { if (!this.container) {
this.container = document.createElement('swp-allday-container'); this.container = document.createElement('swp-allday-container');
header.appendChild(this.container); header.appendChild(this.container);
} }
} }
return this.container; return this.container;
} }
// REMOVED: createGhostColumns() method - no longer needed!
private getAllDayContainer(): HTMLElement | null {
return document.querySelector('swp-calendar-header swp-allday-container');
}
/**
* Handle drag start for all-day events
*/
public handleDragStart(payload: DragStartEventPayload): void {
this.originalEvent = payload.draggedElement;;
this.draggedClone = payload.draggedClone;
if (this.draggedClone) {
const container = this.getAllDayContainer();
if (!container) return;
this.draggedClone.style.gridColumn = this.originalEvent.style.gridColumn;
this.draggedClone.style.gridRow = this.originalEvent.style.gridRow;
console.log('handleDragStart:this.draggedClone', this.draggedClone);
container.appendChild(this.draggedClone);
// Add dragging style
this.draggedClone.classList.add('dragging');
this.draggedClone.style.zIndex = '1000';
this.draggedClone.style.cursor = 'grabbing';
// Make original semi-transparent
this.originalEvent.style.opacity = '0.3';
this.originalEvent.style.userSelect = 'none';
}
}
/** /**
* Render an all-day event with pre-calculated layout * Render an all-day event with pre-calculated layout
@ -77,28 +107,14 @@ export class AllDayEventRenderer {
* Render all-day events for specific period using AllDayEventRenderer * Render all-day events for specific period using AllDayEventRenderer
*/ */
public renderAllDayEventsForPeriod(eventLayouts: EventLayout[]): void { public renderAllDayEventsForPeriod(eventLayouts: EventLayout[]): void {
// Get events from EventManager for the period
// const events = this.eventManager.getEventsForPeriod(startDate, endDate);
// Clear existing all-day events first
this.clearAllDayEvents(); this.clearAllDayEvents();
// Get actual visible dates from DOM headers instead of generating them
// const layouts = this.allDayManager.initAllDayEventsLayout(allDayEvents, weekDates);
// Render each all-day event with pre-calculated layout
eventLayouts.forEach(layout => { eventLayouts.forEach(layout => {
this.renderAllDayEventWithLayout(layout.calenderEvent, layout); this.renderAllDayEventWithLayout(layout.calenderEvent, layout);
}); });
} }
/**
* Clear only all-day events
*/
private clearAllDayEvents(): void { private clearAllDayEvents(): void {
const allDayContainer = document.querySelector('swp-allday-container'); const allDayContainer = document.querySelector('swp-allday-container');
if (allDayContainer) { if (allDayContainer) {

View file

@ -26,25 +26,32 @@ export interface EventRendererStrategy {
handleColumnChange?(payload: DragColumnChangeEventPayload): void; handleColumnChange?(payload: DragColumnChangeEventPayload): void;
handleNavigationCompleted?(): void; handleNavigationCompleted?(): void;
} }
// Abstract methods that subclasses must implement
// private getColumns(container: HTMLElement): HTMLElement[];
// private getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[];
/** /**
* Base class for event renderers with common functionality * Date-based event renderer
*/ */
export abstract class BaseEventRenderer implements EventRendererStrategy { export class DateEventRenderer implements EventRendererStrategy {
protected dateCalculator: DateCalculator;
// Drag and drop state
private draggedClone: HTMLElement | null = null;
private originalEvent: HTMLElement | null = null;
// Resize manager
constructor(dateCalculator?: DateCalculator) { constructor(dateCalculator?: DateCalculator) {
if (!dateCalculator) { if (!dateCalculator) {
DateCalculator.initialize(calendarConfig); DateCalculator.initialize(calendarConfig);
} }
this.dateCalculator = dateCalculator || new DateCalculator(); this.dateCalculator = dateCalculator || new DateCalculator();
this.setupDragEventListeners();
} }
private dateCalculator: DateCalculator;
private draggedClone: HTMLElement | null = null;
private originalEvent: HTMLElement | null = null;
// ============================================ // ============================================
// NEW OVERLAP DETECTION SYSTEM // NEW OVERLAP DETECTION SYSTEM
@ -97,9 +104,6 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
} }
/**
* Apply common drag styling to an element
*/
private applyDragStyling(element: HTMLElement): void { private applyDragStyling(element: HTMLElement): void {
element.classList.add('dragging'); element.classList.add('dragging');
} }
@ -128,7 +132,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
const snappedStartMinutes = Math.round(actualStartMinutes / snapInterval) * snapInterval; const snappedStartMinutes = Math.round(actualStartMinutes / snapInterval) * snapInterval;
if(!clone.dataset.originalDuration) if (!clone.dataset.originalDuration)
throw new DOMException("missing clone.dataset.originalDuration") throw new DOMException("missing clone.dataset.originalDuration")
const endTotalMinutes = snappedStartMinutes + parseInt(clone.dataset.originalDuration); const endTotalMinutes = snappedStartMinutes + parseInt(clone.dataset.originalDuration);
@ -452,17 +456,14 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
}); });
} }
// Abstract methods that subclasses must implement
protected abstract getColumns(container: HTMLElement): HTMLElement[];
protected abstract getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[];
protected renderEvent(event: CalendarEvent): HTMLElement { private renderEvent(event: CalendarEvent): HTMLElement {
const swpEvent = SwpEventElement.fromCalendarEvent(event); const swpEvent = SwpEventElement.fromCalendarEvent(event);
const eventElement = swpEvent.getElement(); const eventElement = swpEvent.getElement();
// Setup resize handles on first mouseover only // Setup resize handles on first mouseover only
eventElement.addEventListener('mouseover', () => { eventElement.addEventListener('mouseover', () => { // TODO: This is not the correct way... we should not add eventlistener on every event
if (eventElement.dataset.hasResizeHandlers !== 'true') { if (eventElement.dataset.hasResizeHandlers !== 'true') {
eventElement.dataset.hasResizeHandlers = 'true'; eventElement.dataset.hasResizeHandlers = 'true';
} }
@ -544,16 +545,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
element.style.minWidth = '50px'; element.style.minWidth = '50px';
}); });
} }
}
/**
* Date-based event renderer
*/
export class DateEventRenderer extends BaseEventRenderer {
constructor(dateCalculator?: DateCalculator) {
super(dateCalculator);
this.setupDragEventListeners();
}
/** /**
* Setup drag event listeners - placeholder method * Setup drag event listeners - placeholder method
@ -585,32 +577,3 @@ export class DateEventRenderer extends BaseEventRenderer {
return columnEvents; return columnEvents;
} }
} }
/**
* Resource-based event renderer
*/
export class ResourceEventRenderer extends BaseEventRenderer {
protected getColumns(container: HTMLElement): HTMLElement[] {
const columns = container.querySelectorAll('swp-resource-column');
return Array.from(columns) as HTMLElement[];
}
protected getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[] {
const resourceName = column.dataset.resource;
if (!resourceName) return [];
const columnEvents = events.filter(event => {
return event.resource?.name === resourceName;
});
return columnEvents;
}
// ============================================
// NEW OVERLAP DETECTION SYSTEM
// All new functions prefixed with new_
// ============================================
protected overlapDetector = new OverlapDetector();
}

View file

@ -142,29 +142,29 @@ export class EventRenderingService {
* Setup all drag event listeners - moved from EventRenderer for better separation of concerns * Setup all drag event listeners - moved from EventRenderer for better separation of concerns
*/ */
private setupDragEventListeners(): void { private setupDragEventListeners(): void {
// Handle drag start
this.eventBus.on('drag:start', (event: Event) => { this.eventBus.on('drag:start', (event: Event) => {
const dragStartPayload = (event as CustomEvent<DragStartEventPayload>).detail; const dragStartPayload = (event as CustomEvent<DragStartEventPayload>).detail;
// Use the draggedElement directly - no need for DOM query
if (dragStartPayload.draggedElement.hasAttribute('data-allday')) {
return;
}
if (dragStartPayload.draggedElement && this.strategy.handleDragStart && dragStartPayload.columnBounds) { if (dragStartPayload.draggedElement && this.strategy.handleDragStart && dragStartPayload.columnBounds) {
this.strategy.handleDragStart(dragStartPayload); this.strategy.handleDragStart(dragStartPayload);
} }
}); });
// Handle drag move
this.eventBus.on('drag:move', (event: Event) => { this.eventBus.on('drag:move', (event: Event) => {
let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail; let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail;
// Filter: Only handle events WITHOUT data-allday attribute (normal timed events)
if (dragEvent.draggedElement.hasAttribute('data-allday')) { if (dragEvent.draggedElement.hasAttribute('data-allday')) {
return; // This is an all-day event, let AllDayManager handle it return;
} }
if (this.strategy.handleDragMove) { if (this.strategy.handleDragMove) {
this.strategy.handleDragMove(dragEvent); this.strategy.handleDragMove(dragEvent);
} }
}); });
// Handle drag auto-scroll
this.eventBus.on('drag:auto-scroll', (event: Event) => { this.eventBus.on('drag:auto-scroll', (event: Event) => {
const { draggedElement, snappedY } = (event as CustomEvent).detail; const { draggedElement, snappedY } = (event as CustomEvent).detail;
if (this.strategy.handleDragAutoScroll) { if (this.strategy.handleDragAutoScroll) {