Renaming part 1
This commit is contained in:
parent
36ac8d18ab
commit
29811fd4b5
20 changed files with 1424 additions and 582 deletions
87
src/renderers/ColumnRenderer.ts
Normal file
87
src/renderers/ColumnRenderer.ts
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Column rendering strategy interface and implementations
|
||||
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { ResourceCalendarData } from '../types/CalendarTypes';
|
||||
|
||||
/**
|
||||
* Interface for column rendering strategies
|
||||
*/
|
||||
export interface ColumnRenderer {
|
||||
render(dayColumns: HTMLElement, context: ColumnRenderContext): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for column rendering
|
||||
*/
|
||||
export interface ColumnRenderContext {
|
||||
currentWeek: Date;
|
||||
config: CalendarConfig;
|
||||
resourceData?: ResourceCalendarData | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date-based column renderer (original functionality)
|
||||
*/
|
||||
export class DateColumnRenderer implements ColumnRenderer {
|
||||
render(dayColumns: HTMLElement, context: ColumnRenderContext): void {
|
||||
const { currentWeek, config } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const weekDays = config.get('weekDays');
|
||||
const daysToShow = dates.slice(0, weekDays);
|
||||
|
||||
console.log('DateColumnRenderer: About to render', daysToShow.length, 'date columns');
|
||||
|
||||
daysToShow.forEach((date) => {
|
||||
const column = document.createElement('swp-day-column');
|
||||
(column as any).dataset.date = this.formatDate(date);
|
||||
|
||||
const eventsLayer = document.createElement('swp-events-layer');
|
||||
column.appendChild(eventsLayer);
|
||||
|
||||
dayColumns.appendChild(column);
|
||||
});
|
||||
}
|
||||
|
||||
private getWeekDates(weekStart: Date): Date[] {
|
||||
const dates: Date[] = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(weekStart.getDate() + i);
|
||||
dates.push(date);
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
private formatDate(date: Date): string {
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource-based column renderer
|
||||
*/
|
||||
export class ResourceColumnRenderer implements ColumnRenderer {
|
||||
render(dayColumns: HTMLElement, context: ColumnRenderContext): void {
|
||||
const { resourceData } = context;
|
||||
|
||||
if (!resourceData) {
|
||||
console.warn('ResourceColumnRenderer: No resource data available for resource columns');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('ResourceColumnRenderer: About to render', resourceData.resources.length, 'resource columns');
|
||||
|
||||
resourceData.resources.forEach((resource) => {
|
||||
const column = document.createElement('swp-resource-column');
|
||||
(column as any).dataset.resource = resource.name;
|
||||
(column as any).dataset.employeeId = resource.employeeId;
|
||||
(column as any).dataset.date = resourceData.date;
|
||||
|
||||
const eventsLayer = document.createElement('swp-events-layer');
|
||||
column.appendChild(eventsLayer);
|
||||
|
||||
dayColumns.appendChild(column);
|
||||
});
|
||||
}
|
||||
}
|
||||
141
src/renderers/EventRenderer.ts
Normal file
141
src/renderers/EventRenderer.ts
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Event rendering strategy interface and implementations
|
||||
|
||||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { DateUtils } from '../utils/DateUtils';
|
||||
|
||||
/**
|
||||
* Interface for event rendering strategies
|
||||
*/
|
||||
export interface EventRendererStrategy {
|
||||
findColumn(event: CalendarEvent): HTMLElement | null;
|
||||
renderEvents(events: CalendarEvent[], config: CalendarConfig): void;
|
||||
clearEvents(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for event renderers with common functionality
|
||||
*/
|
||||
export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||
abstract findColumn(event: CalendarEvent): HTMLElement | null;
|
||||
|
||||
renderEvents(events: CalendarEvent[], config: CalendarConfig): void {
|
||||
console.log('BaseEventRenderer: renderEvents called with', events.length, 'events');
|
||||
|
||||
// Clear existing events first
|
||||
this.clearEvents();
|
||||
|
||||
// Filter out all-day events (handled by GridManager)
|
||||
const nonAllDayEvents = events.filter(event => !event.allDay);
|
||||
console.log('BaseEventRenderer: Rendering', nonAllDayEvents.length, 'non-all-day events');
|
||||
|
||||
// Render each event in the correct column
|
||||
nonAllDayEvents.forEach(event => {
|
||||
const column = this.findColumn(event);
|
||||
|
||||
if (column) {
|
||||
const eventsLayer = column.querySelector('swp-events-layer');
|
||||
if (eventsLayer) {
|
||||
this.renderEvent(event, eventsLayer, config);
|
||||
} else {
|
||||
console.warn('BaseEventRenderer: No events layer found in column for event', event.title);
|
||||
}
|
||||
} else {
|
||||
console.warn('BaseEventRenderer: No column found for event', event.title);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected renderEvent(event: CalendarEvent, container: Element, config: CalendarConfig): void {
|
||||
const eventElement = document.createElement('swp-event');
|
||||
eventElement.dataset.eventId = event.id;
|
||||
eventElement.dataset.type = event.type;
|
||||
|
||||
// Calculate position based on time
|
||||
const position = this.calculateEventPosition(event, config);
|
||||
eventElement.style.position = 'absolute';
|
||||
eventElement.style.top = `${position.top + 1}px`;
|
||||
eventElement.style.height = `${position.height - 1}px`;
|
||||
|
||||
// Set color
|
||||
eventElement.style.backgroundColor = event.metadata?.color || '#3498db';
|
||||
|
||||
// Format time for display
|
||||
const startTime = this.formatTime(event.start);
|
||||
const endTime = this.formatTime(event.end);
|
||||
|
||||
// Create event content
|
||||
eventElement.innerHTML = `
|
||||
<swp-event-time>${startTime} - ${endTime}</swp-event-time>
|
||||
<swp-event-title>${event.title}</swp-event-title>
|
||||
`;
|
||||
|
||||
container.appendChild(eventElement);
|
||||
}
|
||||
|
||||
protected calculateEventPosition(event: CalendarEvent, config: CalendarConfig): { top: number; height: number } {
|
||||
const startDate = new Date(event.start);
|
||||
const endDate = new Date(event.end);
|
||||
|
||||
const dayStartHour = config.get('dayStartHour');
|
||||
const hourHeight = config.get('hourHeight');
|
||||
|
||||
// Calculate minutes from visible day start
|
||||
const startMinutes = startDate.getHours() * 60 + startDate.getMinutes();
|
||||
const endMinutes = endDate.getHours() * 60 + endDate.getMinutes();
|
||||
const dayStartMinutes = dayStartHour * 60;
|
||||
|
||||
// Calculate top position (subtract day start to align with time axis)
|
||||
const top = ((startMinutes - dayStartMinutes) / 60) * hourHeight;
|
||||
|
||||
// Calculate height
|
||||
const durationMinutes = endMinutes - startMinutes;
|
||||
const height = (durationMinutes / 60) * hourHeight;
|
||||
|
||||
return { top, height };
|
||||
}
|
||||
|
||||
protected formatTime(isoString: string): string {
|
||||
const date = new Date(isoString);
|
||||
const hours = date.getHours();
|
||||
const minutes = date.getMinutes();
|
||||
const period = hours >= 12 ? 'PM' : 'AM';
|
||||
const displayHour = hours > 12 ? hours - 12 : (hours === 0 ? 12 : hours);
|
||||
|
||||
return `${displayHour}:${minutes.toString().padStart(2, '0')} ${period}`;
|
||||
}
|
||||
|
||||
clearEvents(): void {
|
||||
const existingEvents = document.querySelectorAll('swp-event');
|
||||
existingEvents.forEach(event => event.remove());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Date-based event renderer
|
||||
*/
|
||||
export class DateEventRenderer extends BaseEventRenderer {
|
||||
findColumn(event: CalendarEvent): HTMLElement | null {
|
||||
const eventDate = new Date(event.start);
|
||||
const dateStr = DateUtils.formatDate(eventDate);
|
||||
const dayColumn = document.querySelector(`swp-day-column[data-date="${dateStr}"]`) as HTMLElement;
|
||||
console.log('DateEventRenderer: Looking for day column with date', dateStr, 'found:', !!dayColumn);
|
||||
return dayColumn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource-based event renderer
|
||||
*/
|
||||
export class ResourceEventRenderer extends BaseEventRenderer {
|
||||
findColumn(event: CalendarEvent): HTMLElement | null {
|
||||
if (!event.resourceName) {
|
||||
console.warn('ResourceEventRenderer: Event has no resourceName', event);
|
||||
return null;
|
||||
}
|
||||
|
||||
const resourceColumn = document.querySelector(`swp-resource-column[data-resource="${event.resourceName}"]`) as HTMLElement;
|
||||
console.log('ResourceEventRenderer: Looking for resource column with name', event.resourceName, 'found:', !!resourceColumn);
|
||||
return resourceColumn;
|
||||
}
|
||||
}
|
||||
158
src/renderers/HeaderRenderer.ts
Normal file
158
src/renderers/HeaderRenderer.ts
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
// Header rendering strategy interface and implementations
|
||||
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { ResourceCalendarData } from '../types/CalendarTypes';
|
||||
|
||||
/**
|
||||
* Interface for header rendering strategies
|
||||
*/
|
||||
export interface HeaderRenderer {
|
||||
render(weekHeader: HTMLElement, context: HeaderRenderContext): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for header rendering
|
||||
*/
|
||||
export interface HeaderRenderContext {
|
||||
currentWeek: Date;
|
||||
config: CalendarConfig;
|
||||
allDayEvents?: any[];
|
||||
resourceData?: ResourceCalendarData | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date-based header renderer (original functionality)
|
||||
*/
|
||||
export class DateHeaderRenderer implements HeaderRenderer {
|
||||
render(weekHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { currentWeek, config, allDayEvents = [] } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const weekDays = config.get('weekDays');
|
||||
const daysToShow = dates.slice(0, weekDays);
|
||||
|
||||
daysToShow.forEach((date) => {
|
||||
const header = document.createElement('swp-day-header');
|
||||
if (this.isToday(date)) {
|
||||
(header as any).dataset.today = 'true';
|
||||
}
|
||||
|
||||
header.innerHTML = `
|
||||
<swp-day-name>${this.getDayName(date)}</swp-day-name>
|
||||
<swp-day-date>${date.getDate()}</swp-day-date>
|
||||
`;
|
||||
(header as any).dataset.date = this.formatDate(date);
|
||||
|
||||
weekHeader.appendChild(header);
|
||||
});
|
||||
|
||||
// Render all-day events in row 2
|
||||
this.renderAllDayEvents(weekHeader, context);
|
||||
}
|
||||
|
||||
private renderAllDayEvents(weekHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { currentWeek, config, allDayEvents = [] } = context;
|
||||
|
||||
const dates = this.getWeekDates(currentWeek);
|
||||
const weekDays = config.get('weekDays');
|
||||
const daysToShow = dates.slice(0, weekDays);
|
||||
|
||||
// Process each all-day event to calculate its span
|
||||
allDayEvents.forEach(event => {
|
||||
const startDate = new Date(event.start);
|
||||
const endDate = new Date(event.end);
|
||||
|
||||
// Find start and end column indices
|
||||
let startColumnIndex = -1;
|
||||
let endColumnIndex = -1;
|
||||
|
||||
daysToShow.forEach((date, index) => {
|
||||
const dateStr = this.formatDate(date);
|
||||
const startDateStr = this.formatDate(startDate);
|
||||
|
||||
if (dateStr === startDateStr) {
|
||||
startColumnIndex = index;
|
||||
}
|
||||
|
||||
// For end date, we need to check if the event spans to this day
|
||||
if (date <= endDate) {
|
||||
endColumnIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
// Only render if the event starts within the visible week
|
||||
if (startColumnIndex >= 0) {
|
||||
// If end column is not found or is before start, default to single day
|
||||
if (endColumnIndex < startColumnIndex) {
|
||||
endColumnIndex = startColumnIndex;
|
||||
}
|
||||
|
||||
const allDayEvent = document.createElement('swp-allday-event');
|
||||
allDayEvent.textContent = event.title;
|
||||
|
||||
// Set grid column span: start column (1-based) to end column + 1 (1-based)
|
||||
const gridColumnStart = startColumnIndex + 1;
|
||||
const gridColumnEnd = endColumnIndex + 2;
|
||||
allDayEvent.style.gridColumn = `${gridColumnStart} / ${gridColumnEnd}`;
|
||||
allDayEvent.style.backgroundColor = event.metadata?.color || '#ff9800';
|
||||
|
||||
weekHeader.appendChild(allDayEvent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getWeekDates(weekStart: Date): Date[] {
|
||||
const dates: Date[] = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const date = new Date(weekStart);
|
||||
date.setDate(weekStart.getDate() + i);
|
||||
dates.push(date);
|
||||
}
|
||||
return dates;
|
||||
}
|
||||
|
||||
private isToday(date: Date): boolean {
|
||||
const today = new Date();
|
||||
return date.toDateString() === today.toDateString();
|
||||
}
|
||||
|
||||
private formatDate(date: Date): string {
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
private getDayName(date: Date): string {
|
||||
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
return days[date.getDay()];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource-based header renderer
|
||||
*/
|
||||
export class ResourceHeaderRenderer implements HeaderRenderer {
|
||||
render(weekHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { resourceData } = context;
|
||||
|
||||
if (!resourceData) {
|
||||
console.warn('ResourceHeaderRenderer: No resource data available for resource headers');
|
||||
return;
|
||||
}
|
||||
|
||||
resourceData.resources.forEach((resource) => {
|
||||
const header = document.createElement('swp-resource-header');
|
||||
header.setAttribute('data-resource', resource.name);
|
||||
header.setAttribute('data-employee-id', resource.employeeId);
|
||||
|
||||
header.innerHTML = `
|
||||
<swp-resource-avatar>
|
||||
<img src="${resource.avatarUrl}" alt="${resource.displayName}" onerror="this.style.display='none'">
|
||||
</swp-resource-avatar>
|
||||
<swp-resource-name>${resource.displayName}</swp-resource-name>
|
||||
`;
|
||||
|
||||
weekHeader.appendChild(header);
|
||||
});
|
||||
|
||||
console.log(`ResourceHeaderRenderer: Rendered ${resourceData.resources.length} resource headers`);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue