Calendar/src/managers/HeaderManager.ts

120 lines
3.5 KiB
TypeScript
Raw Normal View History

import { eventBus } from '../core/EventBus';
import { calendarConfig } from '../core/CalendarConfig';
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
/**
* HeaderManager - Handles all header-related event logic
* Separates event handling from rendering concerns
*/
export class HeaderManager {
private headerEventListener: ((event: Event) => void) | null = null;
private headerMouseLeaveListener: ((event: Event) => void) | null = null;
private cachedCalendarHeader: HTMLElement | null = null;
constructor() {
// Bind methods for event listeners
this.setupHeaderDragListeners = this.setupHeaderDragListeners.bind(this);
this.destroy = this.destroy.bind(this);
}
/**
* Get cached calendar header element
*/
private getCalendarHeader(): HTMLElement | null {
if (!this.cachedCalendarHeader) {
this.cachedCalendarHeader = document.querySelector('swp-calendar-header');
}
return this.cachedCalendarHeader;
}
/**
* Setup header drag event listeners
*/
public setupHeaderDragListeners(): void {
const calendarHeader = this.getCalendarHeader();
if (!calendarHeader) return;
// Clean up existing listeners first
this.removeEventListeners();
// Throttle for better performance
let lastEmitTime = 0;
const throttleDelay = 16; // ~60fps
this.headerEventListener = (event: Event) => {
const now = Date.now();
if (now - lastEmitTime < throttleDelay) {
return; // Throttle events for better performance
}
lastEmitTime = now;
const target = event.target as HTMLElement;
// Optimized element detection - handle day headers and all-day columns
const dayHeader = target.closest('swp-day-header');
const allDayColumn = target.closest('swp-allday-column');
if (dayHeader || allDayColumn) {
const hoveredElement = (dayHeader || allDayColumn) as HTMLElement;
const targetDate = hoveredElement.dataset.date;
// Get header renderer for coordination
const calendarType = calendarConfig.getCalendarMode();
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
eventBus.emit('header:mouseover', {
element: hoveredElement,
targetDate,
headerRenderer
});
}
};
// Header mouseleave listener
this.headerMouseLeaveListener = (event: Event) => {
eventBus.emit('header:mouseleave', {
element: event.target as HTMLElement
});
};
// Add event listeners
calendarHeader.addEventListener('mouseover', this.headerEventListener);
calendarHeader.addEventListener('mouseleave', this.headerMouseLeaveListener);
}
/**
* Remove event listeners from header
*/
private removeEventListeners(): void {
const calendarHeader = this.getCalendarHeader();
if (!calendarHeader) return;
if (this.headerEventListener) {
calendarHeader.removeEventListener('mouseover', this.headerEventListener);
}
if (this.headerMouseLeaveListener) {
calendarHeader.removeEventListener('mouseleave', this.headerMouseLeaveListener);
}
}
/**
* Clear cached header reference
*/
public clearCache(): void {
this.cachedCalendarHeader = null;
}
/**
* Clean up resources and event listeners
*/
public destroy(): void {
this.removeEventListeners();
// Clear references
this.headerEventListener = null;
this.headerMouseLeaveListener = null;
this.clearCache();
}
}