Replaces global singleton configuration with dependency injection Introduces more modular and testable approach to configuration Removes direct references to calendarConfig in multiple components Adds explicit configuration passing to constructors Improves code maintainability and reduces global state dependencies
226 lines
No EOL
6.8 KiB
TypeScript
226 lines
No EOL
6.8 KiB
TypeScript
import { EventBus } from '../core/EventBus';
|
|
import { CalendarView, IEventBus } from '../types/CalendarTypes';
|
|
import { CalendarConfig } from '../core/CalendarConfig';
|
|
import { CoreEvents } from '../constants/CoreEvents';
|
|
|
|
/**
|
|
* ViewManager - Optimized view switching with consolidated event handling
|
|
* Reduces redundant DOM queries and event listener setups
|
|
*/
|
|
export class ViewManager {
|
|
private eventBus: IEventBus;
|
|
private config: CalendarConfig;
|
|
private currentView: CalendarView = 'week';
|
|
private buttonListeners: Map<Element, EventListener> = new Map();
|
|
|
|
// Cached DOM elements for performance
|
|
private cachedViewButtons: NodeListOf<Element> | null = null;
|
|
private cachedWorkweekButtons: NodeListOf<Element> | null = null;
|
|
private lastButtonCacheTime: number = 0;
|
|
private readonly CACHE_DURATION = 5000; // 5 seconds
|
|
|
|
constructor(eventBus: IEventBus, config: CalendarConfig) {
|
|
this.eventBus = eventBus;
|
|
this.config = config;
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
/**
|
|
* Consolidated event listener setup with better organization
|
|
*/
|
|
private setupEventListeners(): void {
|
|
// Event bus listeners
|
|
this.setupEventBusListeners();
|
|
|
|
// DOM button handlers with consolidated logic
|
|
this.setupButtonHandlers();
|
|
}
|
|
|
|
/**
|
|
* Setup event bus listeners with proper cleanup tracking
|
|
*/
|
|
private setupEventBusListeners(): void {
|
|
this.eventBus.on(CoreEvents.INITIALIZED, () => {
|
|
this.initializeView();
|
|
});
|
|
|
|
// Remove redundant VIEW_CHANGED listener that causes circular calls
|
|
// changeView is called directly from button handlers
|
|
|
|
this.eventBus.on(CoreEvents.DATE_CHANGED, () => {
|
|
this.refreshCurrentView();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Consolidated button handler setup with shared logic
|
|
*/
|
|
private setupButtonHandlers(): void {
|
|
// Setup view buttons with consolidated handler
|
|
this.setupButtonGroup('swp-view-button[data-view]', 'data-view', (value) => {
|
|
if (this.isValidView(value)) {
|
|
this.changeView(value as CalendarView);
|
|
}
|
|
});
|
|
|
|
// Setup workweek buttons with consolidated handler
|
|
this.setupButtonGroup('swp-preset-button[data-workweek]', 'data-workweek', (value) => {
|
|
this.changeWorkweek(value);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generic button group setup to eliminate duplicate code
|
|
*/
|
|
private setupButtonGroup(selector: string, attribute: string, handler: (value: string) => void): void {
|
|
const buttons = document.querySelectorAll(selector);
|
|
buttons.forEach(button => {
|
|
const clickHandler = (event: Event) => {
|
|
event.preventDefault();
|
|
const value = button.getAttribute(attribute);
|
|
if (value) {
|
|
handler(value);
|
|
}
|
|
};
|
|
button.addEventListener('click', clickHandler);
|
|
this.buttonListeners.set(button, clickHandler);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get cached view buttons with cache invalidation
|
|
*/
|
|
private getViewButtons(): NodeListOf<Element> {
|
|
const now = Date.now();
|
|
if (!this.cachedViewButtons || (now - this.lastButtonCacheTime) > this.CACHE_DURATION) {
|
|
this.cachedViewButtons = document.querySelectorAll('swp-view-button[data-view]');
|
|
this.lastButtonCacheTime = now;
|
|
}
|
|
return this.cachedViewButtons;
|
|
}
|
|
|
|
/**
|
|
* Get cached workweek buttons with cache invalidation
|
|
*/
|
|
private getWorkweekButtons(): NodeListOf<Element> {
|
|
const now = Date.now();
|
|
if (!this.cachedWorkweekButtons || (now - this.lastButtonCacheTime) > this.CACHE_DURATION) {
|
|
this.cachedWorkweekButtons = document.querySelectorAll('swp-preset-button[data-workweek]');
|
|
this.lastButtonCacheTime = now;
|
|
}
|
|
return this.cachedWorkweekButtons;
|
|
}
|
|
|
|
|
|
/**
|
|
* Initialize view with consolidated button updates
|
|
*/
|
|
private initializeView(): void {
|
|
this.updateAllButtons();
|
|
this.emitViewRendered();
|
|
}
|
|
|
|
/**
|
|
* Optimized view change with debouncing
|
|
*/
|
|
private changeView(newView: CalendarView): void {
|
|
if (newView === this.currentView) return;
|
|
|
|
const previousView = this.currentView;
|
|
this.currentView = newView;
|
|
|
|
this.updateAllButtons();
|
|
|
|
this.eventBus.emit(CoreEvents.VIEW_CHANGED, {
|
|
previousView,
|
|
currentView: newView
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Optimized workweek change with consolidated updates
|
|
*/
|
|
private changeWorkweek(workweekId: string): void {
|
|
// Update the calendar config (does not emit events)
|
|
this.config.setWorkWeek(workweekId);
|
|
|
|
// Update button states using cached elements
|
|
this.updateAllButtons();
|
|
|
|
// Emit workweek change event with full payload
|
|
const settings = this.config.getWorkWeekSettings();
|
|
this.eventBus.emit(CoreEvents.WORKWEEK_CHANGED, {
|
|
workWeekId: workweekId,
|
|
settings: settings
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Consolidated button update method to eliminate duplicate code
|
|
*/
|
|
private updateAllButtons(): void {
|
|
this.updateButtonGroup(
|
|
this.getViewButtons(),
|
|
'data-view',
|
|
this.currentView
|
|
);
|
|
|
|
this.updateButtonGroup(
|
|
this.getWorkweekButtons(),
|
|
'data-workweek',
|
|
this.config.getCurrentWorkWeek()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Generic button group update to eliminate duplicate logic
|
|
*/
|
|
private updateButtonGroup(buttons: NodeListOf<Element>, attribute: string, activeValue: string): void {
|
|
buttons.forEach(button => {
|
|
const buttonValue = button.getAttribute(attribute);
|
|
if (buttonValue === activeValue) {
|
|
button.setAttribute('data-active', 'true');
|
|
} else {
|
|
button.removeAttribute('data-active');
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Emit view rendered event with current view
|
|
*/
|
|
private emitViewRendered(): void {
|
|
this.eventBus.emit(CoreEvents.VIEW_RENDERED, {
|
|
view: this.currentView
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Refresh current view by emitting view rendered event
|
|
*/
|
|
private refreshCurrentView(): void {
|
|
this.emitViewRendered();
|
|
}
|
|
|
|
/**
|
|
* Validate if a string is a valid calendar view
|
|
*/
|
|
private isValidView(view: string): view is CalendarView {
|
|
return ['day', 'week', 'month'].includes(view);
|
|
}
|
|
|
|
/**
|
|
* Get current active view
|
|
*/
|
|
public getCurrentView(): CalendarView {
|
|
return this.currentView;
|
|
}
|
|
|
|
/**
|
|
* Public refresh method
|
|
*/
|
|
public refresh(): void {
|
|
this.refreshCurrentView();
|
|
}
|
|
|
|
} |