Implements a fuzzy search filter system using Fuse.js to enhance event searching. This system allows users to quickly find events by typing partial matches of event titles or descriptions, providing visual feedback by dimming non-matching events. The filter persists during navigation and includes escape key support for quick clearing. It also includes performance optimizations like requestAnimationFrame debouncing.
158 lines
No EOL
5.7 KiB
TypeScript
158 lines
No EOL
5.7 KiB
TypeScript
import { EventBus } from '../core/EventBus';
|
|
import { IEventBus, CalendarEvent, RenderContext } from '../types/CalendarTypes';
|
|
import { CoreEvents } from '../constants/CoreEvents';
|
|
import { calendarConfig } from '../core/CalendarConfig';
|
|
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
|
import { EventManager } from '../managers/EventManager';
|
|
import { EventRendererStrategy } from './EventRenderer';
|
|
|
|
/**
|
|
* EventRenderingService - Render events i DOM med positionering using Strategy Pattern
|
|
* Håndterer event positioning og overlap detection
|
|
*/
|
|
export class EventRenderingService {
|
|
private eventBus: IEventBus;
|
|
private eventManager: EventManager;
|
|
private strategy: EventRendererStrategy;
|
|
|
|
constructor(eventBus: IEventBus, eventManager: EventManager) {
|
|
this.eventBus = eventBus;
|
|
this.eventManager = eventManager;
|
|
|
|
// Cache strategy at initialization
|
|
const calendarType = calendarConfig.getCalendarMode();
|
|
this.strategy = CalendarTypeFactory.getEventRenderer(calendarType);
|
|
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
/**
|
|
* Render events in a specific container for a given period
|
|
*/
|
|
public renderEvents(context: RenderContext): void {
|
|
console.log(` 📅 Getting events for ${context.startDate.toDateString()} - ${context.endDate.toDateString()}`);
|
|
|
|
// Clear existing events in the specific container first
|
|
this.strategy.clearEvents(context.container);
|
|
console.log(` 🧹 Cleared existing events in container`);
|
|
|
|
// Get events from EventManager for the period
|
|
const events = this.eventManager.getEventsForPeriod(
|
|
context.startDate,
|
|
context.endDate
|
|
);
|
|
|
|
console.log(` 📊 Found ${events.length} events for period`);
|
|
|
|
if (events.length === 0) {
|
|
console.log(' ⚠️ No events to render for this period');
|
|
return;
|
|
}
|
|
|
|
// Use cached strategy to render events in the specific container
|
|
this.strategy.renderEvents(events, context.container, calendarConfig);
|
|
|
|
console.log(` ✅ Rendered ${events.length} events successfully`);
|
|
|
|
// Emit EVENTS_RENDERED event for filtering system
|
|
this.eventBus.emit(CoreEvents.EVENTS_RENDERED, {
|
|
events: events,
|
|
container: context.container
|
|
});
|
|
}
|
|
|
|
private setupEventListeners(): void {
|
|
// Event-driven rendering: React to grid and container events
|
|
this.eventBus.on(CoreEvents.GRID_RENDERED, (event: Event) => {
|
|
console.log('EventRenderer: Received GRID_RENDERED event');
|
|
this.handleGridRendered(event as CustomEvent);
|
|
});
|
|
|
|
// CONTAINER_READY_FOR_EVENTS removed - events are now pre-rendered synchronously
|
|
// this.eventBus.on(EventTypes.CONTAINER_READY_FOR_EVENTS, (event: Event) => {
|
|
// console.log('EventRenderer: Received CONTAINER_READY_FOR_EVENTS event');
|
|
// this.handleContainerReady(event as CustomEvent);
|
|
// });
|
|
|
|
this.eventBus.on(CoreEvents.VIEW_CHANGED, (event: Event) => {
|
|
console.log('EventRenderer: Received VIEW_CHANGED event');
|
|
this.handleViewChanged(event as CustomEvent);
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle GRID_RENDERED event - render events in the current grid
|
|
*/
|
|
private handleGridRendered(event: CustomEvent): void {
|
|
const { container, startDate, endDate, currentDate } = event.detail;
|
|
|
|
if (!container) {
|
|
console.error('EventRenderer: No container in GRID_RENDERED event', event.detail);
|
|
return;
|
|
}
|
|
|
|
let periodStart: Date;
|
|
let periodEnd: Date;
|
|
|
|
if (startDate && endDate) {
|
|
// Direct date format - use as provided
|
|
periodStart = startDate;
|
|
periodEnd = endDate;
|
|
} else if (currentDate) {
|
|
console.error('EventRenderer: GRID_RENDERED events must include explicit startDate and endDate', event.detail);
|
|
return;
|
|
} else {
|
|
console.error('EventRenderer: No date information in GRID_RENDERED event', event.detail);
|
|
return;
|
|
}
|
|
|
|
this.renderEvents({
|
|
container: container,
|
|
startDate: periodStart,
|
|
endDate: periodEnd
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
console.error('EventRenderer: Invalid CONTAINER_READY_FOR_EVENTS event data', event.detail);
|
|
return;
|
|
}
|
|
|
|
this.renderEvents({
|
|
container: container,
|
|
startDate: new Date(startDate),
|
|
endDate: new Date(endDate)
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Handle VIEW_CHANGED event - clear and re-render for new view
|
|
*/
|
|
private handleViewChanged(event: CustomEvent): void {
|
|
// Clear all existing events since view structure may have changed
|
|
this.clearEvents();
|
|
|
|
// New rendering will be triggered by subsequent GRID_RENDERED event
|
|
console.log('EventRenderer: Cleared events for view change, waiting for GRID_RENDERED');
|
|
}
|
|
private clearEvents(container?: HTMLElement): void {
|
|
console.log(`EventRenderer: Clearing events`, container ? 'in container' : 'globally');
|
|
this.strategy.clearEvents(container);
|
|
}
|
|
|
|
public refresh(container?: HTMLElement): void {
|
|
// Clear events in specific container or globally
|
|
this.clearEvents(container);
|
|
}
|
|
|
|
public destroy(): void {
|
|
this.clearEvents();
|
|
}
|
|
} |