import { CoreEvents } from '../constants/CoreEvents'; import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils'; /** * EventRenderingService - Render events i DOM med positionering using Strategy Pattern * Håndterer event positioning og overlap detection */ export class EventRenderingService { constructor(eventBus, eventManager, strategy, dateService) { this.dragMouseLeaveHeaderListener = null; this.eventBus = eventBus; this.eventManager = eventManager; this.strategy = strategy; this.dateService = dateService; this.setupEventListeners(); } /** * Render events in a specific container for a given period */ async renderEvents(context) { // Clear existing events in the specific container first this.strategy.clearEvents(context.container); // Get events from EventManager for the period const events = await this.eventManager.getEventsForPeriod(context.startDate, context.endDate); if (events.length === 0) { return; } // Filter events by type - only render timed events here const timedEvents = events.filter(event => !event.allDay); console.log('🎯 EventRenderingService: Event filtering', { totalEvents: events.length, timedEvents: timedEvents.length, allDayEvents: events.length - timedEvents.length }); // Render timed events using existing strategy if (timedEvents.length > 0) { this.strategy.renderEvents(timedEvents, context.container); } // Emit EVENTS_RENDERED event for filtering system this.eventBus.emit(CoreEvents.EVENTS_RENDERED, { events: events, container: context.container }); } setupEventListeners() { this.eventBus.on(CoreEvents.GRID_RENDERED, (event) => { this.handleGridRendered(event); }); this.eventBus.on(CoreEvents.VIEW_CHANGED, (event) => { this.handleViewChanged(event); }); // Handle all drag events and delegate to appropriate renderer this.setupDragEventListeners(); } /** * Handle GRID_RENDERED event - render events in the current grid */ handleGridRendered(event) { const { container, dates } = event.detail; if (!container || !dates || dates.length === 0) { return; } // Calculate startDate and endDate from dates array const startDate = dates[0]; const endDate = dates[dates.length - 1]; this.renderEvents({ container, startDate, endDate }); } /** * Handle VIEW_CHANGED event - clear and re-render for new view */ handleViewChanged(event) { // Clear all existing events since view structure may have changed this.clearEvents(); // New rendering will be triggered by subsequent GRID_RENDERED event } /** * Setup all drag event listeners - moved from EventRenderer for better separation of concerns */ setupDragEventListeners() { this.setupDragStartListener(); this.setupDragMoveListener(); this.setupDragEndListener(); this.setupDragColumnChangeListener(); this.setupDragMouseLeaveHeaderListener(); this.setupDragMouseEnterColumnListener(); this.setupResizeEndListener(); this.setupNavigationCompletedListener(); } setupDragStartListener() { this.eventBus.on('drag:start', (event) => { const dragStartPayload = event.detail; if (dragStartPayload.originalElement.hasAttribute('data-allday')) { return; } if (dragStartPayload.originalElement && this.strategy.handleDragStart && dragStartPayload.columnBounds) { this.strategy.handleDragStart(dragStartPayload); } }); } setupDragMoveListener() { this.eventBus.on('drag:move', (event) => { let dragEvent = event.detail; if (dragEvent.draggedClone.hasAttribute('data-allday')) { return; } if (this.strategy.handleDragMove) { this.strategy.handleDragMove(dragEvent); } }); } setupDragEndListener() { this.eventBus.on('drag:end', async (event) => { const { originalElement, draggedClone, originalSourceColumn, finalPosition, target } = event.detail; const finalColumn = finalPosition.column; const finalY = finalPosition.snappedY; let element = draggedClone; // Only handle day column drops for EventRenderer if (target === 'swp-day-column' && finalColumn) { if (originalElement && draggedClone && this.strategy.handleDragEnd) { this.strategy.handleDragEnd(originalElement, draggedClone, finalColumn, finalY); } await this.eventManager.updateEvent(element.eventId, { start: element.start, end: element.end, allDay: false }); // Re-render affected columns for stacking/grouping (now with updated data) await this.reRenderAffectedColumns(originalSourceColumn, finalColumn); } }); } setupDragColumnChangeListener() { this.eventBus.on('drag:column-change', (event) => { let columnChangeEvent = event.detail; // Filter: Only handle events where clone is NOT an all-day event (normal timed events) if (columnChangeEvent.draggedClone && columnChangeEvent.draggedClone.hasAttribute('data-allday')) { return; } if (this.strategy.handleColumnChange) { this.strategy.handleColumnChange(columnChangeEvent); } }); } setupDragMouseLeaveHeaderListener() { this.dragMouseLeaveHeaderListener = (event) => { const { targetDate, mousePosition, originalElement, draggedClone: cloneElement } = event.detail; if (cloneElement) cloneElement.style.display = ''; console.log('🚪 EventRendererManager: Received drag:mouseleave-header', { targetDate, originalElement: originalElement, cloneElement: cloneElement }); }; this.eventBus.on('drag:mouseleave-header', this.dragMouseLeaveHeaderListener); } setupDragMouseEnterColumnListener() { this.eventBus.on('drag:mouseenter-column', (event) => { const payload = event.detail; // Only handle if clone is an all-day event if (!payload.draggedClone.hasAttribute('data-allday')) { return; } console.log('🎯 EventRendererManager: Received drag:mouseenter-column', { targetColumn: payload.targetColumn, snappedY: payload.snappedY, calendarEvent: payload.calendarEvent }); // Delegate to strategy for conversion if (this.strategy.handleConvertAllDayToTimed) { this.strategy.handleConvertAllDayToTimed(payload); } }); } setupResizeEndListener() { this.eventBus.on('resize:end', async (event) => { const { eventId, element } = event.detail; // Update event data in EventManager with new end time from resized element const swpEvent = element; const newStart = swpEvent.start; const newEnd = swpEvent.end; await this.eventManager.updateEvent(eventId, { start: newStart, end: newEnd }); console.log('📝 EventRendererManager: Updated event after resize', { eventId, newStart, newEnd }); let columnBounds = ColumnDetectionUtils.getColumnBoundsByDate(newStart); if (columnBounds) await this.renderSingleColumn(columnBounds); }); } setupNavigationCompletedListener() { this.eventBus.on(CoreEvents.NAVIGATION_COMPLETED, () => { // Delegate to strategy if it handles navigation if (this.strategy.handleNavigationCompleted) { this.strategy.handleNavigationCompleted(); } }); } /** * Re-render affected columns after drag to recalculate stacking/grouping */ async reRenderAffectedColumns(originalSourceColumn, targetColumn) { // Re-render original source column if exists if (originalSourceColumn) { await this.renderSingleColumn(originalSourceColumn); } // Re-render target column if exists and different from source if (targetColumn && targetColumn.date !== originalSourceColumn?.date) { await this.renderSingleColumn(targetColumn); } } /** * Clear events in a single column's events layer */ clearColumnEvents(eventsLayer) { const existingEvents = eventsLayer.querySelectorAll('swp-event'); const existingGroups = eventsLayer.querySelectorAll('swp-event-group'); existingEvents.forEach(event => event.remove()); existingGroups.forEach(group => group.remove()); } /** * Render events for a single column */ async renderSingleColumn(column) { // Get events for just this column's date const columnStart = this.dateService.parseISO(`${column.date}T00:00:00`); const columnEnd = this.dateService.parseISO(`${column.date}T23:59:59.999`); // Get events from EventManager for this single date const events = await this.eventManager.getEventsForPeriod(columnStart, columnEnd); // Filter to timed events only const timedEvents = events.filter(event => !event.allDay); // Get events layer within this specific column const eventsLayer = column.element.querySelector('swp-events-layer'); if (!eventsLayer) { console.warn('EventRendererManager: Events layer not found in column'); return; } // Clear only this column's events this.clearColumnEvents(eventsLayer); // Render events for this column using strategy if (this.strategy.renderSingleColumnEvents) { this.strategy.renderSingleColumnEvents(column, timedEvents); } console.log('🔄 EventRendererManager: Re-rendered single column', { columnDate: column.date, eventsCount: timedEvents.length }); } clearEvents(container) { this.strategy.clearEvents(container); } refresh(container) { this.clearEvents(container); } } //# sourceMappingURL=EventRendererManager.js.map