Calendar/wwwroot/js/features/all-day/AllDayDomReader.js

175 lines
5.8 KiB
JavaScript
Raw Normal View History

2026-02-03 00:02:25 +01:00
/**
* AllDayDomReader - Centralized DOM reading utilities for all-day services
*
* STATELESS UTILITY - Pure functions for reading DOM state
* - Consistent selectors across all services
* - Unified computed style approach (not inline styles)
* - Type-safe return values
* - Single source of truth for DOM queries
*/
export class AllDayDomReader {
// ============================================
// CONTAINER GETTERS
// ============================================
/**
* Get the all-day events container element
*/
static getAllDayContainer() {
return document.querySelector('swp-calendar-header swp-allday-container');
}
/**
* Get the calendar header element
*/
static getCalendarHeader() {
return document.querySelector('swp-calendar-header');
}
/**
* Get the header spacer element
*/
static getHeaderSpacer() {
return document.querySelector('swp-header-spacer');
}
// ============================================
// EVENT ELEMENT GETTERS
// ============================================
/**
* Get all all-day event elements (excluding overflow indicators)
* Returns raw HTMLElements for DOM manipulation
*/
static getEventElements() {
const container = this.getAllDayContainer();
if (!container)
return [];
return Array.from(container.querySelectorAll('swp-allday-event:not(.max-event-indicator)'));
}
/**
* Get all-day events as ICalendarEvent objects
* Returns parsed data for business logic
*/
static getEventsAsData() {
const elements = this.getEventElements();
return elements
.map(element => {
const eventId = element.dataset.eventId;
const startStr = element.dataset.start;
const endStr = element.dataset.end;
// Validate required fields
if (!eventId || !startStr || !endStr) {
console.warn('AllDayDomReader: Invalid event data in DOM:', element);
return null;
}
const start = new Date(startStr);
const end = new Date(endStr);
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
console.warn('AllDayDomReader: Invalid event dates:', { startStr, endStr });
return null;
}
return {
id: eventId,
title: element.dataset.title || '',
start,
end,
type: element.dataset.type || 'task',
allDay: true,
syncStatus: (element.dataset.syncStatus || 'synced')
};
})
.filter((event) => event !== null);
}
// ============================================
// GRID POSITION READERS
// ============================================
/**
* Get grid row from element using computed style
* Always uses computed style for consistency
*/
static getGridRow(element) {
const computedStyle = window.getComputedStyle(element);
return parseInt(computedStyle.gridRowStart) || 0;
}
/**
* Get grid column range from element using computed style
*/
static getGridColumnRange(element) {
const computedStyle = window.getComputedStyle(element);
return {
start: parseInt(computedStyle.gridColumnStart) || 0,
end: parseInt(computedStyle.gridColumnEnd) || 0
};
}
/**
* Get grid area from element using computed style
*/
static getGridArea(element) {
const computedStyle = window.getComputedStyle(element);
return computedStyle.gridArea;
}
/**
* Calculate max row number from all events
* Uses computed styles for accurate reading
*/
static getMaxRowFromEvents() {
const events = this.getEventElements();
if (events.length === 0)
return 0;
let maxRow = 0;
events.forEach(event => {
const row = this.getGridRow(event);
maxRow = Math.max(maxRow, row);
});
return maxRow;
}
// ============================================
// STATE READERS
// ============================================
/**
* Check if all-day container is expanded
*/
static isExpanded() {
const container = this.getAllDayContainer();
return container?.classList.contains('expanded') || false;
}
/**
* Get current all-day height from CSS variable
*/
static getCurrentHeight() {
const root = document.documentElement;
const heightStr = root.style.getPropertyValue('--all-day-row-height') || '0px';
return parseInt(heightStr) || 0;
}
/**
* Count events in specific column
*/
static countEventsInColumn(columnIndex) {
const events = this.getEventElements();
let count = 0;
events.forEach((event) => {
const { start, end } = this.getGridColumnRange(event);
if (start <= columnIndex && end > columnIndex) {
count++;
}
});
return count;
}
// ============================================
// LAYOUT READERS
// ============================================
/**
* Get current layouts from DOM elements
* Returns map of eventId layout info for comparison
*/
static getCurrentLayouts() {
const layoutsMap = new Map();
const events = this.getEventElements();
events.forEach(event => {
const eventId = event.dataset.eventId;
if (eventId) {
layoutsMap.set(eventId, {
gridArea: this.getGridArea(event)
});
}
});
return layoutsMap;
}
}
//# sourceMappingURL=AllDayDomReader.js.map