Improves all-day event rendering and handling
Refactors all-day event container handling to improve rendering and event delegation. Ensures all-day containers are consistently created and managed, preventing issues with event display and drag-and-drop functionality. Moves event listener setup into dedicated methods for better organization and reusability.
This commit is contained in:
parent
f2763ad826
commit
07402a07d9
6 changed files with 142 additions and 44 deletions
|
|
@ -80,9 +80,11 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear any existing all-day containers first
|
||||
// Clear content of existing all-day containers (but keep the containers)
|
||||
const existingContainers = calendarHeader.querySelectorAll('swp-allday-container');
|
||||
existingContainers.forEach(container => container.remove());
|
||||
existingContainers.forEach(container => {
|
||||
container.innerHTML = ''; // Clear content, keep container
|
||||
});
|
||||
|
||||
// Track maximum number of stacked events to calculate row height
|
||||
let maxStackHeight = 0;
|
||||
|
|
@ -142,20 +144,31 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
|||
}
|
||||
|
||||
const columnSpan = endColumn - startColumn + 1;
|
||||
|
||||
// Create or find container for this column span
|
||||
const containerKey = `${startColumn}-${columnSpan}`;
|
||||
let allDayContainer = calendarHeader.querySelector(`swp-allday-container[data-container-key="${containerKey}"]`);
|
||||
|
||||
let allDayContainer: Element | null = null;
|
||||
|
||||
if (columnSpan === 1) {
|
||||
// Single day event - use existing single-day container
|
||||
const containerKey = `${startColumn}-1`;
|
||||
allDayContainer = calendarHeader.querySelector(`swp-allday-container[data-container-key="${containerKey}"]`);
|
||||
} else {
|
||||
// Multi-day event - create or find spanning container
|
||||
const containerKey = `${startColumn}-${columnSpan}`;
|
||||
allDayContainer = calendarHeader.querySelector(`swp-allday-container[data-container-key="${containerKey}"]`);
|
||||
|
||||
if (!allDayContainer) {
|
||||
// Create container that spans the appropriate columns
|
||||
allDayContainer = document.createElement('swp-allday-container');
|
||||
allDayContainer.setAttribute('data-container-key', containerKey);
|
||||
allDayContainer.setAttribute('data-date', this.dateCalculator.formatISODate(startDate));
|
||||
(allDayContainer as HTMLElement).style.gridColumn = `${startColumn} / span ${columnSpan}`;
|
||||
(allDayContainer as HTMLElement).style.gridRow = '2';
|
||||
calendarHeader.appendChild(allDayContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allDayContainer) {
|
||||
// Create container that spans the appropriate columns
|
||||
allDayContainer = document.createElement('swp-allday-container');
|
||||
allDayContainer.setAttribute('data-container-key', containerKey);
|
||||
(allDayContainer as HTMLElement).style.gridColumn = columnSpan > 1
|
||||
? `${startColumn} / span ${columnSpan}`
|
||||
: `${startColumn}`;
|
||||
(allDayContainer as HTMLElement).style.gridRow = '2';
|
||||
calendarHeader.appendChild(allDayContainer);
|
||||
console.warn(`BaseEventRenderer: No container found for event "${event.title}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the all-day event element inside container
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ export class EventRenderingService {
|
|||
|
||||
// Use cached strategy to render events in the specific container
|
||||
this.strategy.renderEvents(events, context.container, calendarConfig);
|
||||
|
||||
console.log(` ✅ Rendered ${events.length} events successfully`);
|
||||
|
||||
// Emit EVENTS_RENDERED event for filtering system
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { eventBus } from '../core/EventBus';
|
|||
*/
|
||||
export class GridRenderer {
|
||||
private config: CalendarConfig;
|
||||
private headerEventListener: ((event: Event) => void) | null = null;
|
||||
|
||||
constructor(config: CalendarConfig) {
|
||||
this.config = config;
|
||||
|
|
@ -135,31 +136,11 @@ export class GridRenderer {
|
|||
|
||||
headerRenderer.render(calendarHeader, context);
|
||||
|
||||
// Use event delegation for mouseover detection on entire header
|
||||
calendarHeader.addEventListener('mouseover', (event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
|
||||
// Check what was hovered - could be day-header OR all-day-container
|
||||
const dayHeader = target.closest('swp-day-header');
|
||||
const allDayContainer = target.closest('swp-allday-container');
|
||||
|
||||
if (dayHeader || allDayContainer) {
|
||||
const hoveredElement = dayHeader || allDayContainer;
|
||||
const targetDate = (hoveredElement as HTMLElement).dataset.date;
|
||||
|
||||
console.log('GridRenderer: Detected hover over:', {
|
||||
elementType: dayHeader ? 'day-header' : 'all-day-container',
|
||||
targetDate,
|
||||
element: hoveredElement
|
||||
});
|
||||
|
||||
eventBus.emit('header:mouseover', {
|
||||
element: hoveredElement,
|
||||
targetDate,
|
||||
headerRenderer
|
||||
});
|
||||
}
|
||||
});
|
||||
// Always ensure all-day containers exist for all days
|
||||
headerRenderer.ensureAllDayContainers(calendarHeader);
|
||||
|
||||
// Setup event listener for mouseover detection
|
||||
this.setupHeaderEventListener(calendarHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -200,4 +181,47 @@ export class GridRenderer {
|
|||
// Re-render headers using Strategy Pattern - this will also re-attach the event listener
|
||||
this.renderCalendarHeader(calendarHeader as HTMLElement, currentWeek, resourceData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup or re-setup event delegation listener on calendar header
|
||||
*/
|
||||
private setupHeaderEventListener(calendarHeader: HTMLElement): void {
|
||||
// Remove existing listener if any (stored reference approach)
|
||||
if (this.headerEventListener) {
|
||||
calendarHeader.removeEventListener('mouseover', this.headerEventListener);
|
||||
}
|
||||
|
||||
// Create new listener function
|
||||
this.headerEventListener = (event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
|
||||
// Check what was hovered - could be day-header OR all-day-container
|
||||
const dayHeader = target.closest('swp-day-header');
|
||||
const allDayContainer = target.closest('swp-allday-container');
|
||||
|
||||
if (dayHeader || allDayContainer) {
|
||||
const hoveredElement = dayHeader || allDayContainer;
|
||||
const targetDate = (hoveredElement as HTMLElement).dataset.date;
|
||||
|
||||
console.log('GridRenderer: Detected hover over:', {
|
||||
elementType: dayHeader ? 'day-header' : 'all-day-container',
|
||||
targetDate,
|
||||
element: hoveredElement
|
||||
});
|
||||
|
||||
// Get the header renderer for addToAllDay functionality
|
||||
const calendarType = this.config.getCalendarMode();
|
||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
||||
|
||||
eventBus.emit('header:mouseover', {
|
||||
element: hoveredElement,
|
||||
targetDate,
|
||||
headerRenderer
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Add the new listener
|
||||
calendarHeader.addEventListener('mouseover', this.headerEventListener);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import { DateCalculator } from '../utils/DateCalculator';
|
|||
export interface HeaderRenderer {
|
||||
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void;
|
||||
addToAllDay(dayHeader: HTMLElement): void;
|
||||
ensureAllDayContainers(calendarHeader: HTMLElement): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,6 +37,24 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure all-day containers exist for all days (called automatically after header render)
|
||||
*/
|
||||
ensureAllDayContainers(calendarHeader: HTMLElement): void {
|
||||
const root = document.documentElement;
|
||||
const currentHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-row-height') || '0');
|
||||
|
||||
// If all-day row doesn't exist yet, set it up without animation
|
||||
if (currentHeight === 0) {
|
||||
root.style.setProperty('--all-day-row-height', `${ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT}px`);
|
||||
}
|
||||
|
||||
// Always ensure containers exist for all days
|
||||
this.createEmptyAllDayContainers(calendarHeader);
|
||||
|
||||
console.log('BaseHeaderRenderer: Ensured all-day containers exist for all days');
|
||||
}
|
||||
|
||||
private animateHeaderExpansion(calendarHeader: HTMLElement): void {
|
||||
const root = document.documentElement;
|
||||
const currentHeaderHeight = parseInt(getComputedStyle(root).getPropertyValue('--header-height'));
|
||||
|
|
@ -126,7 +145,7 @@ export class DateHeaderRenderer extends BaseHeaderRenderer {
|
|||
private dateCalculator!: DateCalculator;
|
||||
|
||||
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
|
||||
const { currentWeek, config, allDayEvents = [] } = context;
|
||||
const { currentWeek, config } = context;
|
||||
|
||||
// Initialize date calculator with config
|
||||
this.dateCalculator = new DateCalculator(config);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { CoreEvents } from '../constants/CoreEvents';
|
|||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { DateCalculator } from '../utils/DateCalculator';
|
||||
import { EventRenderingService } from './EventRendererManager';
|
||||
import { CalendarTypeFactory } from '../factories/CalendarTypeFactory';
|
||||
import { eventBus } from '../core/EventBus';
|
||||
|
||||
/**
|
||||
* NavigationRenderer - Handles DOM rendering for navigation containers
|
||||
|
|
@ -170,6 +172,13 @@ export class NavigationRenderer {
|
|||
|
||||
header.appendChild(headerElement);
|
||||
});
|
||||
|
||||
// Always ensure all-day containers exist for all days
|
||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(this.config.getCalendarMode());
|
||||
headerRenderer.ensureAllDayContainers(header as HTMLElement);
|
||||
|
||||
// Add event delegation listener for drag & drop functionality
|
||||
this.setupHeaderEventListener(header as HTMLElement);
|
||||
|
||||
// Render day columns for target week
|
||||
dates.forEach(date => {
|
||||
|
|
@ -183,4 +192,38 @@ export class NavigationRenderer {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup event delegation listener for header mouseover (same logic as GridRenderer)
|
||||
*/
|
||||
private setupHeaderEventListener(calendarHeader: HTMLElement): void {
|
||||
calendarHeader.addEventListener('mouseover', (event) => {
|
||||
const target = event.target as HTMLElement;
|
||||
|
||||
// Check what was hovered - could be day-header OR all-day-container
|
||||
const dayHeader = target.closest('swp-day-header');
|
||||
const allDayContainer = target.closest('swp-allday-container');
|
||||
|
||||
if (dayHeader || allDayContainer) {
|
||||
const hoveredElement = dayHeader || allDayContainer;
|
||||
const targetDate = (hoveredElement as HTMLElement).dataset.date;
|
||||
|
||||
console.log('NavigationRenderer: Detected hover over:', {
|
||||
elementType: dayHeader ? 'day-header' : 'all-day-container',
|
||||
targetDate,
|
||||
element: hoveredElement
|
||||
});
|
||||
|
||||
// Get the header renderer for addToAllDay functionality
|
||||
const calendarType = this.config.getCalendarMode();
|
||||
const headerRenderer = CalendarTypeFactory.getHeaderRenderer(calendarType);
|
||||
|
||||
eventBus.emit('header:mouseover', {
|
||||
element: hoveredElement,
|
||||
targetDate,
|
||||
headerRenderer
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,8 +50,8 @@ export class MonthViewStrategy implements ViewStrategy {
|
|||
// Add 6 weeks of day cells
|
||||
this.createDayCells(monthGrid, context.currentDate);
|
||||
|
||||
// Render events in day cells
|
||||
this.renderMonthEvents(monthGrid, context.allDayEvents);
|
||||
// Render events in day cells (will be handled by EventRendererManager)
|
||||
// this.renderMonthEvents(monthGrid, context.allDayEvents);
|
||||
|
||||
context.container.appendChild(monthGrid);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue