diff --git a/src/factories/ManagerFactory.ts b/src/factories/ManagerFactory.ts index d35d38c..569b0b0 100644 --- a/src/factories/ManagerFactory.ts +++ b/src/factories/ManagerFactory.ts @@ -38,7 +38,7 @@ export class ManagerFactory { const navigationManager = new NavigationManager(eventBus, eventRenderer); const viewManager = new ViewManager(eventBus); const dragDropManager = new DragDropManager(eventBus); - const allDayManager = new AllDayManager(); + const allDayManager = new AllDayManager(eventManager); // CalendarManager depends on all other managers const calendarManager = new CalendarManager( diff --git a/src/managers/AllDayManager.ts b/src/managers/AllDayManager.ts index f2d9ac4..f601c5a 100644 --- a/src/managers/AllDayManager.ts +++ b/src/managers/AllDayManager.ts @@ -11,9 +11,12 @@ import { DragStartEventPayload, DragMoveEventPayload, DragEndEventPayload, - DragColumnChangeEventPayload + DragColumnChangeEventPayload, + HeaderReadyEventPayload } from '../types/EventTypes'; import { DragOffset, MousePosition } from '../types/DragDropTypes'; +import { CoreEvents } from '../constants/CoreEvents'; +import { EventManager } from './EventManager'; /** * AllDayManager - Handles all-day row height animations and management @@ -21,12 +24,14 @@ import { DragOffset, MousePosition } from '../types/DragDropTypes'; */ export class AllDayManager { private allDayEventRenderer: AllDayEventRenderer; + private eventManager: EventManager; + private layoutEngine: AllDayLayoutEngine | null = null; // State tracking for differential updates private currentLayouts: EventLayout[] = []; private currentAllDayEvents: CalendarEvent[] = []; - private currentWeekDates: string[] = []; + private currentWeekDates: ColumnBounds[] = []; private newLayouts: EventLayout[] = []; // Expand/collapse state @@ -34,8 +39,8 @@ export class AllDayManager { private actualRowCount: number = 0; private readonly MAX_COLLAPSED_ROWS = 4; // Show 4 rows when collapsed (3 events + 1 indicator row) - - constructor() { + constructor(eventManager: EventManager) { + this.eventManager = eventManager; this.allDayEventRenderer = new AllDayEventRenderer(); this.setupEventListeners(); } @@ -53,7 +58,7 @@ export class AllDayManager { originalElementTag: payload.originalElement?.tagName }); - this.handleConvertToAllDay(payload); + this.handleConvertToAllDay(payload); }); eventBus.on('drag:mouseleave-header', (event) => { @@ -118,6 +123,26 @@ export class AllDayManager { }); + // Listen for header ready - when dates are populated with period data + eventBus.on('header:ready', (event: Event) => { + let headerReadyEventPayload = (event as CustomEvent).detail; + + var startDate = headerReadyEventPayload.headerElements.startDate; + var endDate = headerReadyEventPayload.headerElements.endDate; + + var events: CalendarEvent[] = this.eventManager.getEventsForPeriod(startDate, endDate); + // Filter for all-day events + const allDayEvents = events.filter(event => event.allDay); + + var eventLayouts = this.calculateAllDayEventsLayout(allDayEvents, headerReadyEventPayload.headerElements) + + this.allDayEventRenderer.renderAllDayEventsForPeriod(eventLayouts); + this.checkAndAnimateAllDayHeight(); + }); + + eventBus.on(CoreEvents.VIEW_CHANGED, (event: Event) => { + this.allDayEventRenderer.handleViewChanged(event as CustomEvent); + }); } private getAllDayContainer(): HTMLElement | null { @@ -275,24 +300,11 @@ export class AllDayManager { } - /** - * Set current events and week dates (called by EventRendererManager) - */ - public setCurrentEvents(events: CalendarEvent[], weekDates: string[]): void { - this.currentAllDayEvents = events; - this.currentWeekDates = weekDates; - - console.log('📝 AllDayManager: Set current events', { - eventCount: events.length, - weekDatesCount: weekDates.length - }); - } - /** * Calculate layout for ALL all-day events using AllDayLayoutEngine * This is the correct method that processes all events together for proper overlap detection */ - public calculateAllDayEventsLayout(events: CalendarEvent[], weekDates: string[]): EventLayout[] { + private calculateAllDayEventsLayout(events: CalendarEvent[], weekDates: ColumnBounds[]): EventLayout[] { // Store current state this.currentAllDayEvents = events; @@ -305,19 +317,6 @@ export class AllDayManager { return layoutEngine.calculateLayout(events); } - public initAllDayEventsLayout(events: CalendarEvent[], weekDates: string[]): EventLayout[] { - - // Store current state - this.currentAllDayEvents = events; - this.currentWeekDates = weekDates; - - // Initialize layout engine with provided week dates - var layoutEngine = new AllDayLayoutEngine(weekDates); - - // Calculate layout for all events together - AllDayLayoutEngine handles CalendarEvents directly - this.currentLayouts = layoutEngine.calculateLayout(events); - return this.currentLayouts; - } /** * Handle conversion of timed event to all-day event - SIMPLIFIED @@ -430,7 +429,7 @@ export class AllDayManager { const droppedEvent: CalendarEvent = { id: eventId, - title: dragEndEvent.draggedClone.dataset.title|| '', + title: dragEndEvent.draggedClone.dataset.title || '', start: new Date(eventDate), end: new Date(eventDate), type: eventType, diff --git a/src/managers/HeaderManager.ts b/src/managers/HeaderManager.ts index faa7c07..77f5bcf 100644 --- a/src/managers/HeaderManager.ts +++ b/src/managers/HeaderManager.ts @@ -6,6 +6,8 @@ import { HeaderRenderContext } from '../renderers/HeaderRenderer'; import { ResourceCalendarData } from '../types/CalendarTypes'; import { DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload, HeaderReadyEventPayload } from '../types/EventTypes'; import { DateCalculator } from '../utils/DateCalculator'; +import { PositionUtils } from '../utils/PositionUtils'; +import { ColumnDetectionUtils } from '../utils/ColumnDetectionUtils'; /** * HeaderManager - Handles all header-related event logic @@ -142,10 +144,7 @@ export class HeaderManager { // Notify other managers that header is ready with period data const payload: HeaderReadyEventPayload = { - headerElement: calendarHeader, - startDate: weekStart, - endDate: weekEnd, - isNavigation: false + headerElements: ColumnDetectionUtils.getHeaderColumns(), }; eventBus.emit('header:ready', payload); } diff --git a/src/renderers/AllDayEventRenderer.ts b/src/renderers/AllDayEventRenderer.ts index acdce87..63e977a 100644 --- a/src/renderers/AllDayEventRenderer.ts +++ b/src/renderers/AllDayEventRenderer.ts @@ -1,7 +1,8 @@ import { CalendarEvent } from '../types/CalendarTypes'; import { SwpAllDayEventElement } from '../elements/SwpEventElement'; import { EventLayout } from '../utils/AllDayLayoutEngine'; - +import { ColumnBounds } from '../utils/ColumnDetectionUtils'; +import { EventManager } from '../managers/EventManager'; /** * AllDayEventRenderer - Simple rendering of all-day events * Handles adding and removing all-day events from the header container @@ -38,7 +39,7 @@ export class AllDayEventRenderer { /** * Render an all-day event with pre-calculated layout */ - public renderAllDayEventWithLayout( + private renderAllDayEventWithLayout( event: CalendarEvent, layout: EventLayout ) { @@ -71,4 +72,41 @@ export class AllDayEventRenderer { public clearCache(): void { this.container = null; } + + /** + * Render all-day events for specific period using AllDayEventRenderer + */ + 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(); + + // 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 => { + this.renderAllDayEventWithLayout(layout.calenderEvent, layout); + }); + + + } + /** + * Clear only all-day events + */ + private clearAllDayEvents(): void { + const allDayContainer = document.querySelector('swp-allday-container'); + if (allDayContainer) { + allDayContainer.querySelectorAll('swp-event').forEach(event => event.remove()); + } + } + + public handleViewChanged(event: CustomEvent): void { + this.clearAllDayEvents(); + } } \ No newline at end of file diff --git a/src/renderers/EventRendererManager.ts b/src/renderers/EventRendererManager.ts index 5babfcb..558568d 100644 --- a/src/renderers/EventRendererManager.ts +++ b/src/renderers/EventRendererManager.ts @@ -4,10 +4,8 @@ import { CoreEvents } from '../constants/CoreEvents'; import { calendarConfig } from '../core/CalendarConfig'; import { CalendarTypeFactory } from '../factories/CalendarTypeFactory'; import { EventManager } from '../managers/EventManager'; -import { AllDayManager } from '../managers/AllDayManager'; import { EventRendererStrategy } from './EventRenderer'; import { SwpEventElement } from '../elements/SwpEventElement'; -import { AllDayEventRenderer } from './AllDayEventRenderer'; import { DragStartEventPayload, DragMoveEventPayload, DragEndEventPayload, DragMouseEnterHeaderEventPayload, DragMouseLeaveHeaderEventPayload, DragColumnChangeEventPayload, HeaderReadyEventPayload } from '../types/EventTypes'; /** * EventRenderingService - Render events i DOM med positionering using Strategy Pattern @@ -17,8 +15,6 @@ export class EventRenderingService { private eventBus: IEventBus; private eventManager: EventManager; private strategy: EventRendererStrategy; - private allDayEventRenderer: AllDayEventRenderer; - private allDayManager: AllDayManager; private dragMouseLeaveHeaderListener: ((event: Event) => void) | null = null; @@ -30,10 +26,6 @@ export class EventRenderingService { const calendarType = calendarConfig.getCalendarMode(); this.strategy = CalendarTypeFactory.getEventRenderer(calendarType); - // Initialize all-day event renderer and manager - this.allDayEventRenderer = new AllDayEventRenderer(); - this.allDayManager = new AllDayManager(); - this.setupEventListeners(); } @@ -85,17 +77,6 @@ export class EventRenderingService { this.handleViewChanged(event as CustomEvent); }); - // Listen for header ready - when dates are populated with period data - this.eventBus.on('header:ready', (event: Event) => { - const { startDate, endDate } = (event as CustomEvent).detail; - console.log('🎯 EventRendererManager: Header ready with period data', { - startDate: startDate.toISOString(), - endDate: endDate.toISOString() - }); - - // Render all-day events using period from header - this.renderAllDayEventsForPeriod(startDate, endDate); - }); // Handle all drag events and delegate to appropriate renderer this.setupDragEventListeners(); @@ -145,22 +126,6 @@ export class EventRenderingService { }); } - /** - * Handle CONTAINER_READY_FOR_EVENTS event - render events in pre-rendered container - */ - private handleContainerReady(event: CustomEvent): void { - const { container, startDate, endDate } = event.detail; - - if (!container || !startDate || !endDate) { - return; - } - - this.renderEvents({ - container: container, - startDate: new Date(startDate), - endDate: new Date(endDate) - }); - } /** * Handle VIEW_CHANGED event - clear and re-render for new view @@ -248,12 +213,12 @@ export class EventRenderingService { // Filter: Only handle events where clone is NOT an all-day event (normal timed events) if (columnChangeEvent.draggedClone && columnChangeEvent.draggedClone.hasAttribute('data-allday')) { - return; + return; } if (this.strategy.handleColumnChange) { const eventId = columnChangeEvent.originalElement.dataset.eventId || ''; - this.strategy.handleColumnChange(columnChangeEvent); + this.strategy.handleColumnChange(columnChangeEvent); } }); @@ -338,90 +303,14 @@ export class EventRenderingService { }); } - /** - * Render all-day events for specific period using AllDayEventRenderer - */ - private renderAllDayEventsForPeriod(startDate: Date, endDate: Date): void { - // Get events from EventManager for the period - const events = this.eventManager.getEventsForPeriod(startDate, endDate); - - // Filter for all-day events - const allDayEvents = events.filter(event => event.allDay); - - console.log('🏗️ EventRenderingService: Rendering all-day events', { - period: { - start: startDate.toISOString(), - end: endDate.toISOString() - }, - count: allDayEvents.length, - events: allDayEvents.map(e => ({ id: e.id, title: e.title })) - }); - - // Clear existing all-day events first - this.clearAllDayEvents(); - - // Get actual visible dates from DOM headers instead of generating them - const weekDates = this.getVisibleDatesFromDOM(); - - console.log('🔍 EventRenderingService: Using visible dates from DOM', { - weekDates, - count: weekDates.length - }); - - // Pass current events to AllDayManager for state tracking - this.allDayManager.setCurrentEvents(allDayEvents, weekDates); - - const layouts = this.allDayManager.initAllDayEventsLayout(allDayEvents, weekDates); - - // Render each all-day event with pre-calculated layout - layouts.forEach(layout => { - this.allDayEventRenderer.renderAllDayEventWithLayout(layout.calenderEvent, layout); - }); - - } - - /** - * Clear only all-day events - */ - private clearAllDayEvents(): void { - const allDayContainer = document.querySelector('swp-allday-container'); - if (allDayContainer) { - allDayContainer.querySelectorAll('swp-event').forEach(event => event.remove()); - } - } - private clearEvents(container?: HTMLElement): void { this.strategy.clearEvents(container); - - // Also clear all-day events - this.clearAllDayEvents(); } public refresh(container?: HTMLElement): void { - // Clear events in specific container or globally this.clearEvents(container); } - /** - * Get visible dates from DOM headers - only the dates that are actually displayed - */ - private getVisibleDatesFromDOM(): string[] { - - const dayHeaders = document.querySelectorAll('swp-calendar-header swp-day-header'); - const weekDates: string[] = []; - - dayHeaders.forEach(header => { - const dateAttr = header.getAttribute('data-date'); - if (dateAttr) { - weekDates.push(dateAttr); - } - }); - - - return weekDates; - } - - public destroy(): void { this.clearEvents(); } diff --git a/src/types/EventTypes.ts b/src/types/EventTypes.ts index e2b293f..07b222a 100644 --- a/src/types/EventTypes.ts +++ b/src/types/EventTypes.ts @@ -103,8 +103,6 @@ export interface DragColumnChangeEventPayload { // Header ready event payload export interface HeaderReadyEventPayload { - headerElement: HTMLElement; - startDate: Date; - endDate: Date; - isNavigation?: boolean; + headerElements: ColumnBounds[]; + } \ No newline at end of file diff --git a/src/utils/ColumnDetectionUtils.ts b/src/utils/ColumnDetectionUtils.ts index bf0b4aa..e717f44 100644 --- a/src/utils/ColumnDetectionUtils.ts +++ b/src/utils/ColumnDetectionUtils.ts @@ -87,4 +87,32 @@ export class ColumnDetectionUtils { public static getColumns(): ColumnBounds[] { return [...this.columnBoundsCache]; } + public static getHeaderColumns(): ColumnBounds[] { + + let dayHeaders: ColumnBounds[] = []; + + const dayColumns = document.querySelectorAll('swp-calendar-header swp-day-header'); + let index = 1; + // Cache hver kolonnes x-grænser + dayColumns.forEach(column => { + const rect = column.getBoundingClientRect(); + const date = (column as HTMLElement).dataset.date; + + if (date) { + dayHeaders.push({ + boundingClientRect : rect, + element: column as HTMLElement, + date, + left: rect.left, + right: rect.right, + index: index++ + }); + } + }); + + // Sorter efter x-position (fra venstre til højre) + dayHeaders.sort((a, b) => a.left - b.left); + return dayHeaders; + + } } \ No newline at end of file