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
|
|
@ -1,22 +1,16 @@
|
|||
import { CalendarConfig } from '../core/CalendarConfig.js';
|
||||
import { calendarConfig } from '../core/CalendarConfig.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
|
||||
*/
|
||||
export class PositionUtils {
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(config: CalendarConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert minutes to pixels
|
||||
*/
|
||||
public minutesToPixels(minutes: number): number {
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
public static minutesToPixels(minutes: number): number {
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const pixelsPerHour = gridSettings.hourHeight;
|
||||
return (minutes / 60) * pixelsPerHour;
|
||||
}
|
||||
|
|
@ -24,8 +18,8 @@ export class PositionUtils {
|
|||
/**
|
||||
* Convert pixels to minutes
|
||||
*/
|
||||
public pixelsToMinutes(pixels: number): number {
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
public static pixelsToMinutes(pixels: number): number {
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const pixelsPerHour = gridSettings.hourHeight;
|
||||
return (pixels / pixelsPerHour) * 60;
|
||||
}
|
||||
|
|
@ -33,33 +27,33 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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 gridSettings = this.config.getGridSettings();
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
||||
|
||||
return this.minutesToPixels(minutesFromDayStart);
|
||||
return PositionUtils.minutesToPixels(minutesFromDayStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 gridSettings = this.config.getGridSettings();
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||
const minutesFromDayStart = totalMinutes - dayStartMinutes;
|
||||
|
||||
return this.minutesToPixels(minutesFromDayStart);
|
||||
return PositionUtils.minutesToPixels(minutesFromDayStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixels to time using DateCalculator
|
||||
*/
|
||||
public pixelsToTime(pixels: number): string {
|
||||
const minutes = this.pixelsToMinutes(pixels);
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
public static pixelsToTime(pixels: number): string {
|
||||
const minutes = PositionUtils.pixelsToMinutes(pixels);
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const dayStartMinutes = gridSettings.dayStartHour * 60;
|
||||
const totalMinutes = dayStartMinutes + minutes;
|
||||
|
||||
|
|
@ -69,7 +63,7 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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;
|
||||
height: number;
|
||||
duration: number;
|
||||
|
|
@ -78,19 +72,19 @@ export class PositionUtils {
|
|||
let endPixels: number;
|
||||
|
||||
if (typeof startTime === 'string') {
|
||||
startPixels = this.timeToPixels(startTime);
|
||||
startPixels = PositionUtils.timeToPixels(startTime);
|
||||
} else {
|
||||
startPixels = this.dateToPixels(startTime);
|
||||
startPixels = PositionUtils.dateToPixels(startTime);
|
||||
}
|
||||
|
||||
if (typeof endTime === 'string') {
|
||||
endPixels = this.timeToPixels(endTime);
|
||||
endPixels = PositionUtils.timeToPixels(endTime);
|
||||
} else {
|
||||
endPixels = this.dateToPixels(endTime);
|
||||
endPixels = PositionUtils.dateToPixels(endTime);
|
||||
}
|
||||
|
||||
const height = Math.max(endPixels - startPixels, this.getMinimumEventHeight());
|
||||
const duration = this.pixelsToMinutes(height);
|
||||
const height = Math.max(endPixels - startPixels, PositionUtils.getMinimumEventHeight());
|
||||
const duration = PositionUtils.pixelsToMinutes(height);
|
||||
|
||||
return {
|
||||
top: startPixels,
|
||||
|
|
@ -102,10 +96,10 @@ export class PositionUtils {
|
|||
/**
|
||||
* Snap position til grid interval
|
||||
*/
|
||||
public snapToGrid(pixels: number): number {
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
public static snapToGrid(pixels: number): number {
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const snapInterval = gridSettings.snapInterval;
|
||||
const snapPixels = this.minutesToPixels(snapInterval);
|
||||
const snapPixels = PositionUtils.minutesToPixels(snapInterval);
|
||||
|
||||
return Math.round(pixels / snapPixels) * snapPixels;
|
||||
}
|
||||
|
|
@ -113,9 +107,9 @@ export class PositionUtils {
|
|||
/**
|
||||
* Snap time to interval using DateCalculator
|
||||
*/
|
||||
public snapTimeToInterval(timeString: string): string {
|
||||
public static snapTimeToInterval(timeString: string): string {
|
||||
const totalMinutes = DateCalculator.timeToMinutes(timeString);
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const snapInterval = gridSettings.snapInterval;
|
||||
|
||||
const snappedMinutes = Math.round(totalMinutes / snapInterval) * snapInterval;
|
||||
|
|
@ -125,7 +119,7 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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;
|
||||
width: number;
|
||||
} {
|
||||
|
|
@ -145,14 +139,14 @@ export class PositionUtils {
|
|||
/**
|
||||
* Check om to events overlapper i tid
|
||||
*/
|
||||
public eventsOverlap(
|
||||
start1: string | Date,
|
||||
end1: string | Date,
|
||||
start2: string | Date,
|
||||
public static eventsOverlap(
|
||||
start1: string | Date,
|
||||
end1: string | Date,
|
||||
start2: string | Date,
|
||||
end2: string | Date
|
||||
): boolean {
|
||||
const pos1 = this.calculateEventPosition(start1, end1);
|
||||
const pos2 = this.calculateEventPosition(start2, end2);
|
||||
const pos1 = PositionUtils.calculateEventPosition(start1, end1);
|
||||
const pos2 = PositionUtils.calculateEventPosition(start2, end2);
|
||||
|
||||
const event1End = pos1.top + pos1.height;
|
||||
const event2End = pos2.top + pos2.height;
|
||||
|
|
@ -163,53 +157,53 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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 relativeY = clientY - rect.top;
|
||||
|
||||
// Snap til grid
|
||||
return this.snapToGrid(relativeY);
|
||||
return PositionUtils.snapToGrid(relativeY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Beregn tid fra mouse/touch koordinat
|
||||
*/
|
||||
public getTimeFromCoordinate(clientY: number, containerElement: HTMLElement): string {
|
||||
const position = this.getPositionFromCoordinate(clientY, containerElement);
|
||||
return this.pixelsToTime(position);
|
||||
public static getTimeFromCoordinate(clientY: number, containerElement: HTMLElement): string {
|
||||
const position = PositionUtils.getPositionFromCoordinate(clientY, containerElement);
|
||||
return PositionUtils.pixelsToTime(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 gridSettings = this.config.getGridSettings();
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
return hours >= gridSettings.workStartHour && hours < gridSettings.workEndHour;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 gridSettings = this.config.getGridSettings();
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
return hours >= gridSettings.dayStartHour && hours < gridSettings.dayEndHour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hent minimum event højde i pixels
|
||||
*/
|
||||
public getMinimumEventHeight(): number {
|
||||
public static getMinimumEventHeight(): number {
|
||||
// Minimum 15 minutter
|
||||
return this.minutesToPixels(15);
|
||||
return PositionUtils.minutesToPixels(15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hent maksimum event højde i pixels (hele dagen)
|
||||
*/
|
||||
public getMaximumEventHeight(): number {
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
public static getMaximumEventHeight(): number {
|
||||
const gridSettings = calendarConfig.getGridSettings();
|
||||
const dayDurationHours = gridSettings.dayEndHour - gridSettings.dayStartHour;
|
||||
return dayDurationHours * gridSettings.hourHeight;
|
||||
}
|
||||
|
|
@ -217,14 +211,14 @@ export class PositionUtils {
|
|||
/**
|
||||
* Beregn total kalender højde
|
||||
*/
|
||||
public getTotalCalendarHeight(): number {
|
||||
return this.getMaximumEventHeight();
|
||||
public static getTotalCalendarHeight(): number {
|
||||
return PositionUtils.getMaximumEventHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ISO datetime to time string using DateCalculator
|
||||
*/
|
||||
public isoToTimeString(isoString: string): string {
|
||||
public static isoToTimeString(isoString: string): string {
|
||||
const date = new Date(isoString);
|
||||
return DateCalculator.formatTime(date);
|
||||
}
|
||||
|
|
@ -232,7 +226,7 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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 hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
|
|
@ -246,14 +240,14 @@ export class PositionUtils {
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format duration to readable text (Danish)
|
||||
*/
|
||||
public formatDuration(minutes: number): string {
|
||||
public static formatDuration(minutes: number): string {
|
||||
if (minutes < 60) {
|
||||
return `${minutes} min`;
|
||||
}
|
||||
|
|
@ -267,11 +261,4 @@ export class PositionUtils {
|
|||
|
||||
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