Refactors calendar configuration and event handling
Streamlines calendar configuration by adopting a singleton pattern for consistent access and simplifies event handling.
- Removes direct `CalendarConfig` dependency injection in favor of the `calendarConfig` singleton, reducing code complexity.
- Replaces specific event emissions for grid, date, and resource settings updates with a general `REFRESH_REQUESTED` event.
- Updates event names to be more descriptive and consistent ("NAVIGATION_COMPLETED", "PERIOD_INFO_UPDATE").
- Removes the need to pass the calendar config to renderers since it is now a singleton.
This improves code maintainability and simplifies the event emission process.
This commit is contained in:
parent
d0936d1838
commit
2083c6921e
19 changed files with 139 additions and 173 deletions
|
|
@ -15,8 +15,8 @@ export const CoreEvents = {
|
||||||
|
|
||||||
// Navigation events (3)
|
// Navigation events (3)
|
||||||
DATE_CHANGED: 'nav:date-changed',
|
DATE_CHANGED: 'nav:date-changed',
|
||||||
PERIOD_CHANGED: 'nav:period-changed',
|
NAVIGATION_COMPLETED: 'nav:navigation-completed',
|
||||||
WEEK_CHANGED: 'nav:week-changed',
|
PERIOD_INFO_UPDATE: 'nav:period-info-update',
|
||||||
|
|
||||||
// Data events (4)
|
// Data events (4)
|
||||||
DATA_LOADING: 'data:loading',
|
DATA_LOADING: 'data:loading',
|
||||||
|
|
@ -65,8 +65,8 @@ export const EVENT_MIGRATION_MAP: Record<string, string> = {
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
'calendar:datechanged': CoreEvents.DATE_CHANGED,
|
'calendar:datechanged': CoreEvents.DATE_CHANGED,
|
||||||
'calendar:periodchange': CoreEvents.PERIOD_CHANGED,
|
'calendar:navigationcompleted': CoreEvents.NAVIGATION_COMPLETED,
|
||||||
'calendar:weekchanged': CoreEvents.WEEK_CHANGED,
|
'calendar:periodinfoUpdate': CoreEvents.PERIOD_INFO_UPDATE,
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
'calendar:datafetchstart': CoreEvents.DATA_LOADING,
|
'calendar:datafetchstart': CoreEvents.DATA_LOADING,
|
||||||
|
|
|
||||||
|
|
@ -298,11 +298,10 @@ export class CalendarConfig {
|
||||||
this.config.minEventDuration = updates.snapInterval;
|
this.config.minEventDuration = updates.snapInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit grid settings update event
|
// Grid settings changes trigger general refresh - avoid specific event
|
||||||
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||||
key: 'gridSettings',
|
key: 'gridSettings',
|
||||||
value: this.gridSettings,
|
value: this.gridSettings
|
||||||
oldValue: this.gridSettings
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -319,11 +318,10 @@ export class CalendarConfig {
|
||||||
updateDateViewSettings(updates: Partial<DateViewSettings>): void {
|
updateDateViewSettings(updates: Partial<DateViewSettings>): void {
|
||||||
this.dateViewSettings = { ...this.dateViewSettings, ...updates };
|
this.dateViewSettings = { ...this.dateViewSettings, ...updates };
|
||||||
|
|
||||||
// Emit date view settings update event
|
// Date view settings changes trigger general refresh - avoid specific event
|
||||||
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||||
key: 'dateViewSettings',
|
key: 'dateViewSettings',
|
||||||
value: this.dateViewSettings,
|
value: this.dateViewSettings
|
||||||
oldValue: this.dateViewSettings
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,11 +338,10 @@ export class CalendarConfig {
|
||||||
updateResourceViewSettings(updates: Partial<ResourceViewSettings>): void {
|
updateResourceViewSettings(updates: Partial<ResourceViewSettings>): void {
|
||||||
this.resourceViewSettings = { ...this.resourceViewSettings, ...updates };
|
this.resourceViewSettings = { ...this.resourceViewSettings, ...updates };
|
||||||
|
|
||||||
// Emit resource view settings update event
|
// Resource view settings changes trigger general refresh - avoid specific event
|
||||||
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||||
key: 'resourceViewSettings',
|
key: 'resourceViewSettings',
|
||||||
value: this.resourceViewSettings,
|
value: this.resourceViewSettings
|
||||||
oldValue: this.resourceViewSettings
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,13 @@ export class CalendarTypeFactory {
|
||||||
this.registerRenderers('date', {
|
this.registerRenderers('date', {
|
||||||
headerRenderer: new DateHeaderRenderer(),
|
headerRenderer: new DateHeaderRenderer(),
|
||||||
columnRenderer: new DateColumnRenderer(),
|
columnRenderer: new DateColumnRenderer(),
|
||||||
eventRenderer: new DateEventRenderer(calendarConfig)
|
eventRenderer: new DateEventRenderer()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerRenderers('resource', {
|
this.registerRenderers('resource', {
|
||||||
headerRenderer: new ResourceHeaderRenderer(),
|
headerRenderer: new ResourceHeaderRenderer(),
|
||||||
columnRenderer: new ResourceColumnRenderer(),
|
columnRenderer: new ResourceColumnRenderer(),
|
||||||
eventRenderer: new ResourceEventRenderer(calendarConfig)
|
eventRenderer: new ResourceEventRenderer()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { IEventBus } from '../types/CalendarTypes';
|
import { IEventBus } from '../types/CalendarTypes';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
|
||||||
import { EventManager } from '../managers/EventManager';
|
import { EventManager } from '../managers/EventManager';
|
||||||
import { EventRenderingService } from '../renderers/EventRendererManager';
|
import { EventRenderingService } from '../renderers/EventRendererManager';
|
||||||
import { GridManager } from '../managers/GridManager';
|
import { GridManager } from '../managers/GridManager';
|
||||||
|
|
@ -27,7 +26,7 @@ export class ManagerFactory {
|
||||||
/**
|
/**
|
||||||
* Create all managers with proper dependency injection
|
* Create all managers with proper dependency injection
|
||||||
*/
|
*/
|
||||||
public createManagers(eventBus: IEventBus, config: CalendarConfig): {
|
public createManagers(eventBus: IEventBus): {
|
||||||
eventManager: EventManager;
|
eventManager: EventManager;
|
||||||
eventRenderer: EventRenderingService;
|
eventRenderer: EventRenderingService;
|
||||||
gridManager: GridManager;
|
gridManager: GridManager;
|
||||||
|
|
@ -45,15 +44,14 @@ export class ManagerFactory {
|
||||||
const scrollManager = new ScrollManager();
|
const scrollManager = new ScrollManager();
|
||||||
const navigationManager = new NavigationManager(eventBus, eventRenderer);
|
const navigationManager = new NavigationManager(eventBus, eventRenderer);
|
||||||
const viewManager = new ViewManager(eventBus);
|
const viewManager = new ViewManager(eventBus);
|
||||||
const dragDropManager = new DragDropManager(eventBus, config);
|
const dragDropManager = new DragDropManager(eventBus);
|
||||||
|
|
||||||
// CalendarManager depends on all other managers
|
// CalendarManager depends on all other managers
|
||||||
const calendarManager = new CalendarManager(
|
const calendarManager = new CalendarManager(
|
||||||
eventBus,
|
eventBus,
|
||||||
config,
|
eventManager,
|
||||||
eventManager,
|
gridManager,
|
||||||
gridManager,
|
eventRenderer,
|
||||||
eventRenderer,
|
|
||||||
scrollManager
|
scrollManager
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ async function initializeCalendar(): Promise<void> {
|
||||||
|
|
||||||
// Create managers using factory pattern
|
// Create managers using factory pattern
|
||||||
const managerFactory = ManagerFactory.getInstance();
|
const managerFactory = ManagerFactory.getInstance();
|
||||||
const managers = managerFactory.createManagers(eventBus, config);
|
const managers = managerFactory.createManagers(eventBus);
|
||||||
|
|
||||||
// Enable debug mode for development
|
// Enable debug mode for development
|
||||||
eventBus.setDebug(true);
|
eventBus.setDebug(true);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { EventBus } from '../core/EventBus.js';
|
import { EventBus } from '../core/EventBus.js';
|
||||||
import { CoreEvents } from '../constants/CoreEvents.js';
|
import { CoreEvents } from '../constants/CoreEvents.js';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig.js';
|
import { calendarConfig } from '../core/CalendarConfig.js';
|
||||||
import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes.js';
|
import { CalendarEvent, CalendarView, IEventBus } from '../types/CalendarTypes.js';
|
||||||
import { EventManager } from './EventManager.js';
|
import { EventManager } from './EventManager.js';
|
||||||
import { GridManager } from './GridManager.js';
|
import { GridManager } from './GridManager.js';
|
||||||
|
|
@ -11,11 +11,10 @@ import { EventFilterManager } from './EventFilterManager.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CalendarManager - Main coordinator for all calendar managers
|
* CalendarManager - Main coordinator for all calendar managers
|
||||||
* Uses simple direct method calls instead of complex state management
|
* Uses singleton calendarConfig for consistent configuration access
|
||||||
*/
|
*/
|
||||||
export class CalendarManager {
|
export class CalendarManager {
|
||||||
private eventBus: IEventBus;
|
private eventBus: IEventBus;
|
||||||
private config: CalendarConfig;
|
|
||||||
private eventManager: EventManager;
|
private eventManager: EventManager;
|
||||||
private gridManager: GridManager;
|
private gridManager: GridManager;
|
||||||
private eventRenderer: EventRenderingService;
|
private eventRenderer: EventRenderingService;
|
||||||
|
|
@ -28,20 +27,18 @@ export class CalendarManager {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
eventBus: IEventBus,
|
eventBus: IEventBus,
|
||||||
config: CalendarConfig,
|
|
||||||
eventManager: EventManager,
|
eventManager: EventManager,
|
||||||
gridManager: GridManager,
|
gridManager: GridManager,
|
||||||
eventRenderer: EventRenderingService,
|
eventRenderer: EventRenderingService,
|
||||||
scrollManager: ScrollManager
|
scrollManager: ScrollManager
|
||||||
) {
|
) {
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.config = config;
|
|
||||||
this.eventManager = eventManager;
|
this.eventManager = eventManager;
|
||||||
this.gridManager = gridManager;
|
this.gridManager = gridManager;
|
||||||
this.eventRenderer = eventRenderer;
|
this.eventRenderer = eventRenderer;
|
||||||
this.scrollManager = scrollManager;
|
this.scrollManager = scrollManager;
|
||||||
this.eventFilterManager = new EventFilterManager();
|
this.eventFilterManager = new EventFilterManager();
|
||||||
DateCalculator.initialize(config);
|
DateCalculator.initialize(calendarConfig);
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +54,7 @@ export class CalendarManager {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Debug: Check calendar type
|
// Debug: Check calendar type
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
|
|
||||||
// Step 1: Load data
|
// Step 1: Load data
|
||||||
await this.eventManager.loadData();
|
await this.eventManager.loadData();
|
||||||
|
|
@ -194,8 +191,8 @@ export class CalendarManager {
|
||||||
/**
|
/**
|
||||||
* Hent calendar konfiguration
|
* Hent calendar konfiguration
|
||||||
*/
|
*/
|
||||||
public getConfig(): CalendarConfig {
|
public getConfig() {
|
||||||
return this.config;
|
return calendarConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -267,7 +264,7 @@ export class CalendarManager {
|
||||||
nextDate.setDate(nextDate.getDate() + 1);
|
nextDate.setDate(nextDate.getDate() + 1);
|
||||||
break;
|
break;
|
||||||
case 'week':
|
case 'week':
|
||||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
const workWeekSettings = calendarConfig.getWorkWeekSettings();
|
||||||
nextDate.setDate(nextDate.getDate() + 7); // Move to next calendar week regardless of work days
|
nextDate.setDate(nextDate.getDate() + 7); // Move to next calendar week regardless of work days
|
||||||
break;
|
break;
|
||||||
case 'month':
|
case 'month':
|
||||||
|
|
@ -289,7 +286,7 @@ export class CalendarManager {
|
||||||
previousDate.setDate(previousDate.getDate() - 1);
|
previousDate.setDate(previousDate.getDate() - 1);
|
||||||
break;
|
break;
|
||||||
case 'week':
|
case 'week':
|
||||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
const workWeekSettings = calendarConfig.getWorkWeekSettings();
|
||||||
previousDate.setDate(previousDate.getDate() - 7); // Move to previous calendar week regardless of work days
|
previousDate.setDate(previousDate.getDate() - 7); // Move to previous calendar week regardless of work days
|
||||||
break;
|
break;
|
||||||
case 'month':
|
case 'month':
|
||||||
|
|
@ -441,7 +438,7 @@ export class CalendarManager {
|
||||||
const dateRange = DateCalculator.formatDateRange(firstDate, lastDate);
|
const dateRange = DateCalculator.formatDateRange(firstDate, lastDate);
|
||||||
|
|
||||||
// Emit week info update
|
// Emit week info update
|
||||||
this.eventBus.emit(CoreEvents.WEEK_CHANGED, {
|
this.eventBus.emit(CoreEvents.PERIOD_INFO_UPDATE, {
|
||||||
weekNumber,
|
weekNumber,
|
||||||
dateRange,
|
dateRange,
|
||||||
weekStart: firstDate,
|
weekStart: firstDate,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IEventBus } from '../types/CalendarTypes';
|
import { IEventBus } from '../types/CalendarTypes';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { DateCalculator } from '../utils/DateCalculator';
|
import { DateCalculator } from '../utils/DateCalculator';
|
||||||
|
|
||||||
interface CachedElements {
|
interface CachedElements {
|
||||||
|
|
@ -20,7 +20,6 @@ interface Position {
|
||||||
|
|
||||||
export class DragDropManager {
|
export class DragDropManager {
|
||||||
private eventBus: IEventBus;
|
private eventBus: IEventBus;
|
||||||
private config: CalendarConfig;
|
|
||||||
|
|
||||||
// Mouse tracking with optimized state
|
// Mouse tracking with optimized state
|
||||||
private isMouseDown = false;
|
private isMouseDown = false;
|
||||||
|
|
@ -61,12 +60,11 @@ export class DragDropManager {
|
||||||
return (this.snapIntervalMinutes / 60) * this.hourHeightPx;
|
return (this.snapIntervalMinutes / 60) * this.hourHeightPx;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(eventBus: IEventBus, config: CalendarConfig) {
|
constructor(eventBus: IEventBus) {
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.config = config;
|
|
||||||
|
|
||||||
// Get config values
|
// Get config values
|
||||||
const gridSettings = config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
this.hourHeightPx = gridSettings.hourHeight;
|
this.hourHeightPx = gridSettings.hourHeight;
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export class GridManager {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Initialize GridRenderer with config
|
// Initialize GridRenderer with config
|
||||||
this.gridRenderer = new GridRenderer(calendarConfig);
|
this.gridRenderer = new GridRenderer();
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ export class GridManager {
|
||||||
|
|
||||||
this.currentDate = nextDate;
|
this.currentDate = nextDate;
|
||||||
|
|
||||||
eventBus.emit(CoreEvents.PERIOD_CHANGED, {
|
eventBus.emit(CoreEvents.NAVIGATION_COMPLETED, {
|
||||||
direction: 'next',
|
direction: 'next',
|
||||||
newDate: nextDate,
|
newDate: nextDate,
|
||||||
periodLabel: this.getCurrentPeriodLabel()
|
periodLabel: this.getCurrentPeriodLabel()
|
||||||
|
|
@ -182,7 +182,7 @@ export class GridManager {
|
||||||
|
|
||||||
this.currentDate = prevDate;
|
this.currentDate = prevDate;
|
||||||
|
|
||||||
eventBus.emit(CoreEvents.PERIOD_CHANGED, {
|
eventBus.emit(CoreEvents.NAVIGATION_COMPLETED, {
|
||||||
direction: 'previous',
|
direction: 'previous',
|
||||||
newDate: prevDate,
|
newDate: prevDate,
|
||||||
periodLabel: this.getCurrentPeriodLabel()
|
periodLabel: this.getCurrentPeriodLabel()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export class NavigationManager {
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
DateCalculator.initialize(calendarConfig);
|
DateCalculator.initialize(calendarConfig);
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
this.navigationRenderer = new NavigationRenderer(eventBus, calendarConfig, eventRenderer);
|
this.navigationRenderer = new NavigationRenderer(eventBus, eventRenderer);
|
||||||
this.currentWeek = DateCalculator.getISOWeekStart(new Date());
|
this.currentWeek = DateCalculator.getISOWeekStart(new Date());
|
||||||
this.targetWeek = new Date(this.currentWeek);
|
this.targetWeek = new Date(this.currentWeek);
|
||||||
this.init();
|
this.init();
|
||||||
|
|
@ -239,7 +239,7 @@ export class NavigationManager {
|
||||||
this.updateWeekInfo();
|
this.updateWeekInfo();
|
||||||
|
|
||||||
// Emit period change event for ScrollManager
|
// Emit period change event for ScrollManager
|
||||||
this.eventBus.emit(CoreEvents.PERIOD_CHANGED, {
|
this.eventBus.emit(CoreEvents.NAVIGATION_COMPLETED, {
|
||||||
direction,
|
direction,
|
||||||
weekStart: this.currentWeek
|
weekStart: this.currentWeek
|
||||||
});
|
});
|
||||||
|
|
@ -253,7 +253,7 @@ export class NavigationManager {
|
||||||
const dateRange = DateCalculator.formatDateRange(this.currentWeek, weekEnd);
|
const dateRange = DateCalculator.formatDateRange(this.currentWeek, weekEnd);
|
||||||
|
|
||||||
// Notify other managers about week info update - DOM manipulation should happen via events
|
// Notify other managers about week info update - DOM manipulation should happen via events
|
||||||
this.eventBus.emit(CoreEvents.WEEK_CHANGED, {
|
this.eventBus.emit(CoreEvents.PERIOD_INFO_UPDATE, {
|
||||||
weekNumber,
|
weekNumber,
|
||||||
dateRange,
|
dateRange,
|
||||||
weekStart: this.currentWeek,
|
weekStart: this.currentWeek,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export class ScrollManager {
|
||||||
|
|
||||||
private subscribeToEvents(): void {
|
private subscribeToEvents(): void {
|
||||||
// Handle navigation animation completion - sync time axis position
|
// Handle navigation animation completion - sync time axis position
|
||||||
eventBus.on(CoreEvents.PERIOD_CHANGED, () => {
|
eventBus.on(CoreEvents.NAVIGATION_COMPLETED, () => {
|
||||||
this.syncTimeAxisPosition();
|
this.syncTimeAxisPosition();
|
||||||
this.setupScrolling();
|
this.setupScrolling();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Work hours management for per-column scheduling
|
// Work hours management for per-column scheduling
|
||||||
|
|
||||||
import { DateCalculator } from '../utils/DateCalculator';
|
import { DateCalculator } from '../utils/DateCalculator';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Work hours for a specific day
|
* Work hours for a specific day
|
||||||
|
|
@ -33,13 +33,11 @@ export interface WorkScheduleConfig {
|
||||||
* Manages work hours scheduling with weekly defaults and date-specific overrides
|
* Manages work hours scheduling with weekly defaults and date-specific overrides
|
||||||
*/
|
*/
|
||||||
export class WorkHoursManager {
|
export class WorkHoursManager {
|
||||||
private config: CalendarConfig;
|
|
||||||
private dateCalculator: DateCalculator;
|
private dateCalculator: DateCalculator;
|
||||||
private workSchedule: WorkScheduleConfig;
|
private workSchedule: WorkScheduleConfig;
|
||||||
|
|
||||||
constructor(config: CalendarConfig) {
|
constructor() {
|
||||||
this.config = config;
|
DateCalculator.initialize(calendarConfig);
|
||||||
DateCalculator.initialize(config);
|
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
|
|
||||||
// Default work schedule - will be loaded from JSON later
|
// Default work schedule - will be loaded from JSON later
|
||||||
|
|
@ -100,7 +98,7 @@ export class WorkHoursManager {
|
||||||
return null; // Full day will be colored via CSS background
|
return null; // Full day will be colored via CSS background
|
||||||
}
|
}
|
||||||
|
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartHour = gridSettings.dayStartHour;
|
const dayStartHour = gridSettings.dayStartHour;
|
||||||
const dayEndHour = gridSettings.dayEndHour;
|
const dayEndHour = gridSettings.dayEndHour;
|
||||||
const hourHeight = gridSettings.hourHeight;
|
const hourHeight = gridSettings.hourHeight;
|
||||||
|
|
@ -125,7 +123,7 @@ export class WorkHoursManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartHour = gridSettings.dayStartHour;
|
const dayStartHour = gridSettings.dayStartHour;
|
||||||
const hourHeight = gridSettings.hourHeight;
|
const hourHeight = gridSettings.hourHeight;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export class DateColumnRenderer implements ColumnRenderer {
|
||||||
// Initialize date calculator and work hours manager
|
// Initialize date calculator and work hours manager
|
||||||
DateCalculator.initialize(config);
|
DateCalculator.initialize(config);
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
this.workHoursManager = new WorkHoursManager(config);
|
this.workHoursManager = new WorkHoursManager();
|
||||||
|
|
||||||
const dates = DateCalculator.getWorkWeekDates(currentWeek);
|
const dates = DateCalculator.getWorkWeekDates(currentWeek);
|
||||||
const dateSettings = config.getDateViewSettings();
|
const dateSettings = config.getDateViewSettings();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { CalendarEvent } from '../types/CalendarTypes';
|
import { CalendarEvent } from '../types/CalendarTypes';
|
||||||
import { ALL_DAY_CONSTANTS } from '../core/CalendarConfig';
|
import { ALL_DAY_CONSTANTS } from '../core/CalendarConfig';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { DateCalculator } from '../utils/DateCalculator';
|
import { DateCalculator } from '../utils/DateCalculator';
|
||||||
import { eventBus } from '../core/EventBus';
|
import { eventBus } from '../core/EventBus';
|
||||||
import { CoreEvents } from '../constants/CoreEvents';
|
import { CoreEvents } from '../constants/CoreEvents';
|
||||||
|
|
@ -11,7 +11,7 @@ import { CoreEvents } from '../constants/CoreEvents';
|
||||||
* Interface for event rendering strategies
|
* Interface for event rendering strategies
|
||||||
*/
|
*/
|
||||||
export interface EventRendererStrategy {
|
export interface EventRendererStrategy {
|
||||||
renderEvents(events: CalendarEvent[], container: HTMLElement, config: CalendarConfig): void;
|
renderEvents(events: CalendarEvent[], container: HTMLElement): void;
|
||||||
clearEvents(container?: HTMLElement): void;
|
clearEvents(container?: HTMLElement): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,16 +20,14 @@ export interface EventRendererStrategy {
|
||||||
*/
|
*/
|
||||||
export abstract class BaseEventRenderer implements EventRendererStrategy {
|
export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
protected dateCalculator: DateCalculator;
|
protected dateCalculator: DateCalculator;
|
||||||
protected config: CalendarConfig;
|
|
||||||
|
|
||||||
// Drag and drop state
|
// Drag and drop state
|
||||||
private draggedClone: HTMLElement | null = null;
|
private draggedClone: HTMLElement | null = null;
|
||||||
private originalEvent: HTMLElement | null = null;
|
private originalEvent: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor(config: CalendarConfig, dateCalculator?: DateCalculator) {
|
constructor(dateCalculator?: DateCalculator) {
|
||||||
this.config = config;
|
|
||||||
if (!dateCalculator) {
|
if (!dateCalculator) {
|
||||||
DateCalculator.initialize(config);
|
DateCalculator.initialize(calendarConfig);
|
||||||
}
|
}
|
||||||
this.dateCalculator = dateCalculator || new DateCalculator();
|
this.dateCalculator = dateCalculator || new DateCalculator();
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +67,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle navigation period change (when slide animation completes)
|
// Handle navigation period change (when slide animation completes)
|
||||||
eventBus.on(CoreEvents.PERIOD_CHANGED, () => {
|
eventBus.on(CoreEvents.NAVIGATION_COMPLETED, () => {
|
||||||
// Animate all-day height after navigation completes
|
// Animate all-day height after navigation completes
|
||||||
this.triggerAllDayHeightAnimation();
|
this.triggerAllDayHeightAnimation();
|
||||||
});
|
});
|
||||||
|
|
@ -146,7 +144,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
* Update clone timestamp based on new position
|
* Update clone timestamp based on new position
|
||||||
*/
|
*/
|
||||||
private updateCloneTimestamp(clone: HTMLElement, snappedY: number): void {
|
private updateCloneTimestamp(clone: HTMLElement, snappedY: number): void {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const hourHeight = gridSettings.hourHeight;
|
const hourHeight = gridSettings.hourHeight;
|
||||||
const dayStartHour = gridSettings.dayStartHour;
|
const dayStartHour = gridSettings.dayStartHour;
|
||||||
const snapInterval = 15; // TODO: Get from config
|
const snapInterval = 15; // TODO: Get from config
|
||||||
|
|
@ -175,7 +173,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
* Calculate event duration in minutes from element height
|
* Calculate event duration in minutes from element height
|
||||||
*/
|
*/
|
||||||
private getEventDuration(element: HTMLElement): number {
|
private getEventDuration(element: HTMLElement): number {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const hourHeight = gridSettings.hourHeight;
|
const hourHeight = gridSettings.hourHeight;
|
||||||
|
|
||||||
// Get height from style or computed
|
// Get height from style or computed
|
||||||
|
|
@ -424,7 +422,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
renderEvents(events: CalendarEvent[], container: HTMLElement, config: CalendarConfig): void {
|
renderEvents(events: CalendarEvent[], container: HTMLElement): void {
|
||||||
|
|
||||||
// NOTE: Removed clearEvents() to support sliding animation
|
// NOTE: Removed clearEvents() to support sliding animation
|
||||||
// With sliding animation, multiple grid containers exist simultaneously
|
// With sliding animation, multiple grid containers exist simultaneously
|
||||||
|
|
@ -437,7 +435,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
|
|
||||||
|
|
||||||
// Always call renderAllDayEvents to ensure height is set correctly (even to 0)
|
// Always call renderAllDayEvents to ensure height is set correctly (even to 0)
|
||||||
this.renderAllDayEvents(allDayEvents, container, config);
|
this.renderAllDayEvents(allDayEvents, container);
|
||||||
|
|
||||||
// Find columns in the specific container for regular events
|
// Find columns in the specific container for regular events
|
||||||
const columns = this.getColumns(container);
|
const columns = this.getColumns(container);
|
||||||
|
|
@ -448,7 +446,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
const eventsLayer = column.querySelector('swp-events-layer');
|
const eventsLayer = column.querySelector('swp-events-layer');
|
||||||
if (eventsLayer) {
|
if (eventsLayer) {
|
||||||
columnEvents.forEach(event => {
|
columnEvents.forEach(event => {
|
||||||
this.renderEvent(event, eventsLayer, config);
|
this.renderEvent(event, eventsLayer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Debug: Verify events were actually added
|
// Debug: Verify events were actually added
|
||||||
|
|
@ -465,7 +463,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
/**
|
/**
|
||||||
* Render all-day events in the header row 2
|
* Render all-day events in the header row 2
|
||||||
*/
|
*/
|
||||||
protected renderAllDayEvents(allDayEvents: CalendarEvent[], container: HTMLElement, config: CalendarConfig): void {
|
protected renderAllDayEvents(allDayEvents: CalendarEvent[], container: HTMLElement): void {
|
||||||
|
|
||||||
// Find the calendar header
|
// Find the calendar header
|
||||||
const calendarHeader = container.querySelector('swp-calendar-header');
|
const calendarHeader = container.querySelector('swp-calendar-header');
|
||||||
|
|
@ -565,7 +563,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderEvent(event: CalendarEvent, container: Element, config: CalendarConfig): void {
|
protected renderEvent(event: CalendarEvent, container: Element): void {
|
||||||
const eventElement = document.createElement('swp-event');
|
const eventElement = document.createElement('swp-event');
|
||||||
eventElement.dataset.eventId = event.id;
|
eventElement.dataset.eventId = event.id;
|
||||||
eventElement.dataset.title = event.title;
|
eventElement.dataset.title = event.title;
|
||||||
|
|
@ -575,7 +573,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
eventElement.dataset.duration = event.metadata?.duration?.toString() || '60';
|
eventElement.dataset.duration = event.metadata?.duration?.toString() || '60';
|
||||||
|
|
||||||
// Calculate position based on time
|
// Calculate position based on time
|
||||||
const position = this.calculateEventPosition(event, config);
|
const position = this.calculateEventPosition(event);
|
||||||
eventElement.style.position = 'absolute';
|
eventElement.style.position = 'absolute';
|
||||||
eventElement.style.top = `${position.top + 1}px`;
|
eventElement.style.top = `${position.top + 1}px`;
|
||||||
eventElement.style.height = `${position.height - 3}px`; //adjusted so bottom does not cover horizontal time lines.
|
eventElement.style.height = `${position.height - 3}px`; //adjusted so bottom does not cover horizontal time lines.
|
||||||
|
|
@ -601,11 +599,11 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
container.appendChild(eventElement);
|
container.appendChild(eventElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected calculateEventPosition(event: CalendarEvent, config: CalendarConfig): { top: number; height: number } {
|
protected calculateEventPosition(event: CalendarEvent): { top: number; height: number } {
|
||||||
const startDate = new Date(event.start);
|
const startDate = new Date(event.start);
|
||||||
const endDate = new Date(event.end);
|
const endDate = new Date(event.end);
|
||||||
|
|
||||||
const gridSettings = config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartHour = gridSettings.dayStartHour;
|
const dayStartHour = gridSettings.dayStartHour;
|
||||||
const hourHeight = gridSettings.hourHeight;
|
const hourHeight = gridSettings.hourHeight;
|
||||||
|
|
||||||
|
|
@ -681,8 +679,8 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
* Date-based event renderer
|
* Date-based event renderer
|
||||||
*/
|
*/
|
||||||
export class DateEventRenderer extends BaseEventRenderer {
|
export class DateEventRenderer extends BaseEventRenderer {
|
||||||
constructor(config: CalendarConfig, dateCalculator?: DateCalculator) {
|
constructor(dateCalculator?: DateCalculator) {
|
||||||
super(config, dateCalculator);
|
super(dateCalculator);
|
||||||
this.setupDragEventListeners();
|
this.setupDragEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export class EventRenderingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use cached strategy to render events in the specific container
|
// Use cached strategy to render events in the specific container
|
||||||
this.strategy.renderEvents(events, context.container, calendarConfig);
|
this.strategy.renderEvents(events, context.container);
|
||||||
|
|
||||||
// Emit EVENTS_RENDERED event for filtering system
|
// Emit EVENTS_RENDERED event for filtering system
|
||||||
this.eventBus.emit(CoreEvents.EVENTS_RENDERED, {
|
this.eventBus.emit(CoreEvents.EVENTS_RENDERED, {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
|
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
|
||||||
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
||||||
import { HeaderRenderContext } from './HeaderRenderer';
|
import { HeaderRenderContext } from './HeaderRenderer';
|
||||||
|
|
@ -11,14 +11,12 @@ import { DateCalculator } from '../utils/DateCalculator';
|
||||||
* Optimized to reduce redundant DOM operations and improve performance
|
* Optimized to reduce redundant DOM operations and improve performance
|
||||||
*/
|
*/
|
||||||
export class GridRenderer {
|
export class GridRenderer {
|
||||||
private config: CalendarConfig;
|
|
||||||
private headerEventListener: ((event: Event) => void) | null = null;
|
private headerEventListener: ((event: Event) => void) | null = null;
|
||||||
private cachedGridContainer: HTMLElement | null = null;
|
private cachedGridContainer: HTMLElement | null = null;
|
||||||
private cachedCalendarHeader: HTMLElement | null = null;
|
private cachedCalendarHeader: HTMLElement | null = null;
|
||||||
private cachedTimeAxis: HTMLElement | null = null;
|
private cachedTimeAxis: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor(config: CalendarConfig) {
|
constructor() {
|
||||||
this.config = config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -83,7 +81,7 @@ export class GridRenderer {
|
||||||
private createOptimizedTimeAxis(): HTMLElement {
|
private createOptimizedTimeAxis(): HTMLElement {
|
||||||
const timeAxis = document.createElement('swp-time-axis');
|
const timeAxis = document.createElement('swp-time-axis');
|
||||||
const timeAxisContent = document.createElement('swp-time-axis-content');
|
const timeAxisContent = document.createElement('swp-time-axis-content');
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const startHour = gridSettings.dayStartHour;
|
const startHour = gridSettings.dayStartHour;
|
||||||
const endHour = gridSettings.dayEndHour;
|
const endHour = gridSettings.dayEndHour;
|
||||||
|
|
||||||
|
|
@ -146,12 +144,12 @@ export class GridRenderer {
|
||||||
resourceData: ResourceCalendarData | null,
|
resourceData: ResourceCalendarData | null,
|
||||||
view: CalendarView
|
view: CalendarView
|
||||||
): void {
|
): void {
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
||||||
|
|
||||||
const context: HeaderRenderContext = {
|
const context: HeaderRenderContext = {
|
||||||
currentWeek: currentDate, // HeaderRenderer expects currentWeek property
|
currentWeek: currentDate, // HeaderRenderer expects currentWeek property
|
||||||
config: this.config,
|
config: calendarConfig,
|
||||||
resourceData: resourceData
|
resourceData: resourceData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -173,12 +171,12 @@ export class GridRenderer {
|
||||||
resourceData: ResourceCalendarData | null,
|
resourceData: ResourceCalendarData | null,
|
||||||
view: CalendarView
|
view: CalendarView
|
||||||
): void {
|
): void {
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
const columnRenderer = CalendarTypeFactory.getColumnRenderer(calendarType);
|
const columnRenderer = CalendarTypeFactory.getColumnRenderer(calendarType);
|
||||||
|
|
||||||
const context: ColumnRenderContext = {
|
const context: ColumnRenderContext = {
|
||||||
currentWeek: currentDate, // ColumnRenderer expects currentWeek property
|
currentWeek: currentDate, // ColumnRenderer expects currentWeek property
|
||||||
config: this.config,
|
config: calendarConfig,
|
||||||
resourceData: resourceData
|
resourceData: resourceData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -260,7 +258,7 @@ export class GridRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get header renderer once and cache
|
// Get header renderer once and cache
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
||||||
|
|
||||||
eventBus.emit('header:mouseover', {
|
eventBus.emit('header:mouseover', {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { ResourceCalendarData } from '../types/CalendarTypes';
|
import { ResourceCalendarData } from '../types/CalendarTypes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -6,10 +6,7 @@ import { ResourceCalendarData } from '../types/CalendarTypes';
|
||||||
* Separated from GridManager to follow Single Responsibility Principle
|
* Separated from GridManager to follow Single Responsibility Principle
|
||||||
*/
|
*/
|
||||||
export class GridStyleManager {
|
export class GridStyleManager {
|
||||||
private config: CalendarConfig;
|
constructor() {
|
||||||
|
|
||||||
constructor(config: CalendarConfig) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,9 +14,9 @@ export class GridStyleManager {
|
||||||
*/
|
*/
|
||||||
public updateGridStyles(resourceData: ResourceCalendarData | null = null): void {
|
public updateGridStyles(resourceData: ResourceCalendarData | null = null): void {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const calendar = document.querySelector('swp-calendar') as HTMLElement;
|
const calendar = document.querySelector('swp-calendar') as HTMLElement;
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
|
|
||||||
// Set CSS variables for time and grid measurements
|
// Set CSS variables for time and grid measurements
|
||||||
this.setTimeVariables(root, gridSettings);
|
this.setTimeVariables(root, gridSettings);
|
||||||
|
|
@ -58,8 +55,8 @@ export class GridStyleManager {
|
||||||
if (calendarType === 'resource' && resourceData) {
|
if (calendarType === 'resource' && resourceData) {
|
||||||
return resourceData.resources.length;
|
return resourceData.resources.length;
|
||||||
} else if (calendarType === 'date') {
|
} else if (calendarType === 'date') {
|
||||||
const dateSettings = this.config.getDateViewSettings();
|
const dateSettings = calendarConfig.getDateViewSettings();
|
||||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
const workWeekSettings = calendarConfig.getWorkWeekSettings();
|
||||||
|
|
||||||
switch (dateSettings.period) {
|
switch (dateSettings.period) {
|
||||||
case 'day':
|
case 'day':
|
||||||
|
|
@ -73,7 +70,7 @@ export class GridStyleManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.config.getWorkWeekSettings().totalDays; // Default to work week
|
return calendarConfig.getWorkWeekSettings().totalDays; // Default to work week
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { IEventBus } from '../types/CalendarTypes';
|
import { IEventBus } from '../types/CalendarTypes';
|
||||||
import { CoreEvents } from '../constants/CoreEvents';
|
import { CoreEvents } from '../constants/CoreEvents';
|
||||||
import { CalendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
import { DateCalculator } from '../utils/DateCalculator';
|
import { DateCalculator } from '../utils/DateCalculator';
|
||||||
import { EventRenderingService } from './EventRendererManager';
|
import { EventRenderingService } from './EventRendererManager';
|
||||||
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
||||||
|
|
@ -12,7 +12,6 @@ import { eventBus } from '../core/EventBus';
|
||||||
*/
|
*/
|
||||||
export class NavigationRenderer {
|
export class NavigationRenderer {
|
||||||
private eventBus: IEventBus;
|
private eventBus: IEventBus;
|
||||||
private config: CalendarConfig;
|
|
||||||
private dateCalculator: DateCalculator;
|
private dateCalculator: DateCalculator;
|
||||||
private eventRenderer: EventRenderingService;
|
private eventRenderer: EventRenderingService;
|
||||||
|
|
||||||
|
|
@ -20,11 +19,10 @@ export class NavigationRenderer {
|
||||||
private cachedWeekNumberElement: HTMLElement | null = null;
|
private cachedWeekNumberElement: HTMLElement | null = null;
|
||||||
private cachedDateRangeElement: HTMLElement | null = null;
|
private cachedDateRangeElement: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor(eventBus: IEventBus, config: CalendarConfig, eventRenderer: EventRenderingService) {
|
constructor(eventBus: IEventBus, eventRenderer: EventRenderingService) {
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.config = config;
|
|
||||||
this.eventRenderer = eventRenderer;
|
this.eventRenderer = eventRenderer;
|
||||||
DateCalculator.initialize(config);
|
DateCalculator.initialize(calendarConfig);
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +59,7 @@ export class NavigationRenderer {
|
||||||
* Setup event listeners for DOM updates
|
* Setup event listeners for DOM updates
|
||||||
*/
|
*/
|
||||||
private setupEventListeners(): void {
|
private setupEventListeners(): void {
|
||||||
this.eventBus.on(CoreEvents.WEEK_CHANGED, (event: Event) => {
|
this.eventBus.on(CoreEvents.PERIOD_INFO_UPDATE, (event: Event) => {
|
||||||
const customEvent = event as CustomEvent;
|
const customEvent = event as CustomEvent;
|
||||||
const { weekNumber, dateRange } = customEvent.detail;
|
const { weekNumber, dateRange } = customEvent.detail;
|
||||||
this.updateWeekInfoInDOM(weekNumber, dateRange);
|
this.updateWeekInfoInDOM(weekNumber, dateRange);
|
||||||
|
|
@ -201,7 +199,7 @@ export class NavigationRenderer {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Always ensure all-day containers exist for all days
|
// Always ensure all-day containers exist for all days
|
||||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(this.config.getCalendarMode());
|
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarConfig.getCalendarMode());
|
||||||
headerRenderer.ensureAllDayContainers(header as HTMLElement);
|
headerRenderer.ensureAllDayContainers(header as HTMLElement);
|
||||||
|
|
||||||
// Add event delegation listener for drag & drop functionality
|
// Add event delegation listener for drag & drop functionality
|
||||||
|
|
@ -256,7 +254,7 @@ export class NavigationRenderer {
|
||||||
|
|
||||||
|
|
||||||
// Get the header renderer for addToAllDay functionality
|
// Get the header renderer for addToAllDay functionality
|
||||||
const calendarType = this.config.getCalendarMode();
|
const calendarType = calendarConfig.getCalendarMode();
|
||||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
||||||
|
|
||||||
eventBus.emit('header:mouseover', {
|
eventBus.emit('header:mouseover', {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export class WeekViewStrategy implements ViewStrategy {
|
||||||
constructor() {
|
constructor() {
|
||||||
DateCalculator.initialize(calendarConfig);
|
DateCalculator.initialize(calendarConfig);
|
||||||
this.dateCalculator = new DateCalculator();
|
this.dateCalculator = new DateCalculator();
|
||||||
this.gridRenderer = new GridRenderer(calendarConfig);
|
this.gridRenderer = new GridRenderer();
|
||||||
this.styleManager = new GridStyleManager(calendarConfig);
|
this.styleManager = new GridStyleManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
getLayoutConfig(): ViewLayoutConfig {
|
getLayoutConfig(): ViewLayoutConfig {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,16 @@
|
||||||
import { CalendarConfig } from '../core/CalendarConfig.js';
|
import { calendarConfig } from '../core/CalendarConfig.js';
|
||||||
import { DateCalculator } from './DateCalculator.js';
|
import { DateCalculator } from './DateCalculator.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PositionUtils - Optimized positioning utilities using DateCalculator
|
* PositionUtils - Static positioning utilities using singleton calendarConfig
|
||||||
* Focuses on pixel/position calculations while delegating date operations
|
* Focuses on pixel/position calculations while delegating date operations
|
||||||
*/
|
*/
|
||||||
export class PositionUtils {
|
export class PositionUtils {
|
||||||
private config: CalendarConfig;
|
|
||||||
|
|
||||||
constructor(config: CalendarConfig) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert minutes to pixels
|
* Convert minutes to pixels
|
||||||
*/
|
*/
|
||||||
public minutesToPixels(minutes: number): number {
|
public static minutesToPixels(minutes: number): number {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const pixelsPerHour = gridSettings.hourHeight;
|
const pixelsPerHour = gridSettings.hourHeight;
|
||||||
return (minutes / 60) * pixelsPerHour;
|
return (minutes / 60) * pixelsPerHour;
|
||||||
}
|
}
|
||||||
|
|
@ -24,8 +18,8 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Convert pixels to minutes
|
* Convert pixels to minutes
|
||||||
*/
|
*/
|
||||||
public pixelsToMinutes(pixels: number): number {
|
public static pixelsToMinutes(pixels: number): number {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const pixelsPerHour = gridSettings.hourHeight;
|
const pixelsPerHour = gridSettings.hourHeight;
|
||||||
return (pixels / pixelsPerHour) * 60;
|
return (pixels / pixelsPerHour) * 60;
|
||||||
}
|
}
|
||||||
|
|
@ -33,33 +27,33 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Convert time (HH:MM) to pixels from day start using DateCalculator
|
* Convert time (HH:MM) to pixels from day start using DateCalculator
|
||||||
*/
|
*/
|
||||||
public timeToPixels(timeString: string): number {
|
public static timeToPixels(timeString: string): number {
|
||||||
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||||
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
||||||
|
|
||||||
return this.minutesToPixels(minutesFromDayStart);
|
return PositionUtils.minutesToPixels(minutesFromDayStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Date object to pixels from day start using DateCalculator
|
* Convert Date object to pixels from day start using DateCalculator
|
||||||
*/
|
*/
|
||||||
public dateToPixels(date: Date): number {
|
public static dateToPixels(date: Date): number {
|
||||||
const totalMinutes = DateCalculator.getMinutesSinceMidnight(date);
|
const totalMinutes = DateCalculator.getMinutesSinceMidnight(date);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||||
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
||||||
|
|
||||||
return this.minutesToPixels(minutesFromDayStart);
|
return PositionUtils.minutesToPixels(minutesFromDayStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert pixels to time using DateCalculator
|
* Convert pixels to time using DateCalculator
|
||||||
*/
|
*/
|
||||||
public pixelsToTime(pixels: number): string {
|
public static pixelsToTime(pixels: number): string {
|
||||||
const minutes = this.pixelsToMinutes(pixels);
|
const minutes = PositionUtils.pixelsToMinutes(pixels);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||||
const totalMinutes = dayStartMinutes + minutes;
|
const totalMinutes = dayStartMinutes + minutes;
|
||||||
|
|
||||||
|
|
@ -69,7 +63,7 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Beregn event position og størrelse
|
* Beregn event position og størrelse
|
||||||
*/
|
*/
|
||||||
public calculateEventPosition(startTime: string | Date, endTime: string | Date): {
|
public static calculateEventPosition(startTime: string | Date, endTime: string | Date): {
|
||||||
top: number;
|
top: number;
|
||||||
height: number;
|
height: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
|
|
@ -78,19 +72,19 @@ export class PositionUtils {
|
||||||
let endPixels: number;
|
let endPixels: number;
|
||||||
|
|
||||||
if (typeof startTime === 'string') {
|
if (typeof startTime === 'string') {
|
||||||
startPixels = this.timeToPixels(startTime);
|
startPixels = PositionUtils.timeToPixels(startTime);
|
||||||
} else {
|
} else {
|
||||||
startPixels = this.dateToPixels(startTime);
|
startPixels = PositionUtils.dateToPixels(startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof endTime === 'string') {
|
if (typeof endTime === 'string') {
|
||||||
endPixels = this.timeToPixels(endTime);
|
endPixels = PositionUtils.timeToPixels(endTime);
|
||||||
} else {
|
} else {
|
||||||
endPixels = this.dateToPixels(endTime);
|
endPixels = PositionUtils.dateToPixels(endTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const height = Math.max(endPixels - startPixels, this.getMinimumEventHeight());
|
const height = Math.max(endPixels - startPixels, PositionUtils.getMinimumEventHeight());
|
||||||
const duration = this.pixelsToMinutes(height);
|
const duration = PositionUtils.pixelsToMinutes(height);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
top: startPixels,
|
top: startPixels,
|
||||||
|
|
@ -102,10 +96,10 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Snap position til grid interval
|
* Snap position til grid interval
|
||||||
*/
|
*/
|
||||||
public snapToGrid(pixels: number): number {
|
public static snapToGrid(pixels: number): number {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const snapInterval = gridSettings.snapInterval;
|
const snapInterval = gridSettings.snapInterval;
|
||||||
const snapPixels = this.minutesToPixels(snapInterval);
|
const snapPixels = PositionUtils.minutesToPixels(snapInterval);
|
||||||
|
|
||||||
return Math.round(pixels / snapPixels) * snapPixels;
|
return Math.round(pixels / snapPixels) * snapPixels;
|
||||||
}
|
}
|
||||||
|
|
@ -113,9 +107,9 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Snap time to interval using DateCalculator
|
* Snap time to interval using DateCalculator
|
||||||
*/
|
*/
|
||||||
public snapTimeToInterval(timeString: string): string {
|
public static snapTimeToInterval(timeString: string): string {
|
||||||
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const snapInterval = gridSettings.snapInterval;
|
const snapInterval = gridSettings.snapInterval;
|
||||||
|
|
||||||
const snappedMinutes = Math.round(totalMinutes / snapInterval) * snapInterval;
|
const snappedMinutes = Math.round(totalMinutes / snapInterval) * snapInterval;
|
||||||
|
|
@ -125,7 +119,7 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Beregn kolonne position for overlappende events
|
* Beregn kolonne position for overlappende events
|
||||||
*/
|
*/
|
||||||
public calculateColumnPosition(eventIndex: number, totalColumns: number, containerWidth: number): {
|
public static calculateColumnPosition(eventIndex: number, totalColumns: number, containerWidth: number): {
|
||||||
left: number;
|
left: number;
|
||||||
width: number;
|
width: number;
|
||||||
} {
|
} {
|
||||||
|
|
@ -145,14 +139,14 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Check om to events overlapper i tid
|
* Check om to events overlapper i tid
|
||||||
*/
|
*/
|
||||||
public eventsOverlap(
|
public static eventsOverlap(
|
||||||
start1: string | Date,
|
start1: string | Date,
|
||||||
end1: string | Date,
|
end1: string | Date,
|
||||||
start2: string | Date,
|
start2: string | Date,
|
||||||
end2: string | Date
|
end2: string | Date
|
||||||
): boolean {
|
): boolean {
|
||||||
const pos1 = this.calculateEventPosition(start1, end1);
|
const pos1 = PositionUtils.calculateEventPosition(start1, end1);
|
||||||
const pos2 = this.calculateEventPosition(start2, end2);
|
const pos2 = PositionUtils.calculateEventPosition(start2, end2);
|
||||||
|
|
||||||
const event1End = pos1.top + pos1.height;
|
const event1End = pos1.top + pos1.height;
|
||||||
const event2End = pos2.top + pos2.height;
|
const event2End = pos2.top + pos2.height;
|
||||||
|
|
@ -163,53 +157,53 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Beregn Y position fra mouse/touch koordinat
|
* Beregn Y position fra mouse/touch koordinat
|
||||||
*/
|
*/
|
||||||
public getPositionFromCoordinate(clientY: number, containerElement: HTMLElement): number {
|
public static getPositionFromCoordinate(clientY: number, containerElement: HTMLElement): number {
|
||||||
const rect = containerElement.getBoundingClientRect();
|
const rect = containerElement.getBoundingClientRect();
|
||||||
const relativeY = clientY - rect.top;
|
const relativeY = clientY - rect.top;
|
||||||
|
|
||||||
// Snap til grid
|
// Snap til grid
|
||||||
return this.snapToGrid(relativeY);
|
return PositionUtils.snapToGrid(relativeY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Beregn tid fra mouse/touch koordinat
|
* Beregn tid fra mouse/touch koordinat
|
||||||
*/
|
*/
|
||||||
public getTimeFromCoordinate(clientY: number, containerElement: HTMLElement): string {
|
public static getTimeFromCoordinate(clientY: number, containerElement: HTMLElement): string {
|
||||||
const position = this.getPositionFromCoordinate(clientY, containerElement);
|
const position = PositionUtils.getPositionFromCoordinate(clientY, containerElement);
|
||||||
return this.pixelsToTime(position);
|
return PositionUtils.pixelsToTime(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valider at tid er inden for arbejdstimer
|
* Valider at tid er inden for arbejdstimer
|
||||||
*/
|
*/
|
||||||
public isWithinWorkHours(timeString: string): boolean {
|
public static isWithinWorkHours(timeString: string): boolean {
|
||||||
const [hours] = timeString.split(':').map(Number);
|
const [hours] = timeString.split(':').map(Number);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
return hours >= gridSettings.workStartHour && hours < gridSettings.workEndHour;
|
return hours >= gridSettings.workStartHour && hours < gridSettings.workEndHour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valider at tid er inden for dag grænser
|
* Valider at tid er inden for dag grænser
|
||||||
*/
|
*/
|
||||||
public isWithinDayBounds(timeString: string): boolean {
|
public static isWithinDayBounds(timeString: string): boolean {
|
||||||
const [hours] = timeString.split(':').map(Number);
|
const [hours] = timeString.split(':').map(Number);
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
return hours >= gridSettings.dayStartHour && hours < gridSettings.dayEndHour;
|
return hours >= gridSettings.dayStartHour && hours < gridSettings.dayEndHour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hent minimum event højde i pixels
|
* Hent minimum event højde i pixels
|
||||||
*/
|
*/
|
||||||
public getMinimumEventHeight(): number {
|
public static getMinimumEventHeight(): number {
|
||||||
// Minimum 15 minutter
|
// Minimum 15 minutter
|
||||||
return this.minutesToPixels(15);
|
return PositionUtils.minutesToPixels(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hent maksimum event højde i pixels (hele dagen)
|
* Hent maksimum event højde i pixels (hele dagen)
|
||||||
*/
|
*/
|
||||||
public getMaximumEventHeight(): number {
|
public static getMaximumEventHeight(): number {
|
||||||
const gridSettings = this.config.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
const dayDurationHours = gridSettings.dayEndHour - gridSettings.dayStartHour;
|
const dayDurationHours = gridSettings.dayEndHour - gridSettings.dayStartHour;
|
||||||
return dayDurationHours * gridSettings.hourHeight;
|
return dayDurationHours * gridSettings.hourHeight;
|
||||||
}
|
}
|
||||||
|
|
@ -217,14 +211,14 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Beregn total kalender højde
|
* Beregn total kalender højde
|
||||||
*/
|
*/
|
||||||
public getTotalCalendarHeight(): number {
|
public static getTotalCalendarHeight(): number {
|
||||||
return this.getMaximumEventHeight();
|
return PositionUtils.getMaximumEventHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert ISO datetime to time string using DateCalculator
|
* Convert ISO datetime to time string using DateCalculator
|
||||||
*/
|
*/
|
||||||
public isoToTimeString(isoString: string): string {
|
public static isoToTimeString(isoString: string): string {
|
||||||
const date = new Date(isoString);
|
const date = new Date(isoString);
|
||||||
return DateCalculator.formatTime(date);
|
return DateCalculator.formatTime(date);
|
||||||
}
|
}
|
||||||
|
|
@ -232,7 +226,7 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Convert time string to ISO datetime using DateCalculator
|
* Convert time string to ISO datetime using DateCalculator
|
||||||
*/
|
*/
|
||||||
public timeStringToIso(timeString: string, date: Date = new Date()): string {
|
public static timeStringToIso(timeString: string, date: Date = new Date()): string {
|
||||||
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
||||||
const hours = Math.floor(totalMinutes / 60);
|
const hours = Math.floor(totalMinutes / 60);
|
||||||
const minutes = totalMinutes % 60;
|
const minutes = totalMinutes % 60;
|
||||||
|
|
@ -246,14 +240,14 @@ export class PositionUtils {
|
||||||
/**
|
/**
|
||||||
* Calculate event duration using DateCalculator
|
* Calculate event duration using DateCalculator
|
||||||
*/
|
*/
|
||||||
public calculateDuration(startTime: string | Date, endTime: string | Date): number {
|
public static calculateDuration(startTime: string | Date, endTime: string | Date): number {
|
||||||
return DateCalculator.getDurationMinutes(startTime, endTime);
|
return DateCalculator.getDurationMinutes(startTime, endTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format duration to readable text (Danish)
|
* Format duration to readable text (Danish)
|
||||||
*/
|
*/
|
||||||
public formatDuration(minutes: number): string {
|
public static formatDuration(minutes: number): string {
|
||||||
if (minutes < 60) {
|
if (minutes < 60) {
|
||||||
return `${minutes} min`;
|
return `${minutes} min`;
|
||||||
}
|
}
|
||||||
|
|
@ -267,11 +261,4 @@ export class PositionUtils {
|
||||||
|
|
||||||
return `${hours}t ${remainingMinutes}m`;
|
return `${hours}t ${remainingMinutes}m`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Opdater konfiguration
|
|
||||||
*/
|
|
||||||
public updateConfig(newConfig: CalendarConfig): void {
|
|
||||||
this.config = newConfig;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue