Improves all-day event rendering and placement
Simplifies and improves the all-day event rendering process, ensuring consistent container creation and proper placement of events. - Ensures all-day containers are consistently created during header rendering, preventing potential issues with event placement. - Removes the complex and unreliable mouseover detection for all-day conversion, simplifying the event dragging logic. - Eliminates the dynamic all-day row height calculation, relying on CSS for layout control. - Prevents errors when the all-day container is missing.
This commit is contained in:
parent
fafad16926
commit
ae42de1f3b
4 changed files with 15 additions and 105 deletions
|
|
@ -63,83 +63,8 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
const { eventId, targetDate, headerRenderer } = (event as CustomEvent).detail;
|
const { eventId, targetDate, headerRenderer } = (event as CustomEvent).detail;
|
||||||
this.handleConvertToAllDay(eventId, targetDate, headerRenderer);
|
this.handleConvertToAllDay(eventId, targetDate, headerRenderer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for header mouseover events (like original ColumnDetector)
|
|
||||||
eventBus.on('header:mouseover', (event) => {
|
|
||||||
const { element, targetDate, headerRenderer } = (event as CustomEvent).detail;
|
|
||||||
|
|
||||||
if (this.draggedClone && targetDate) {
|
|
||||||
// Scenario 1: Timed event being dragged to header - convert to all-day
|
|
||||||
if (this.draggedClone.tagName === 'SWP-EVENT') {
|
|
||||||
headerRenderer.addToAllDay(element);
|
|
||||||
this.convertToAllDayPreview(targetDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scenario 2: All-day event being moved to different day
|
|
||||||
else if (this.draggedClone.tagName === 'SWP-ALLDAY-EVENT') {
|
|
||||||
const currentDate = this.draggedClone.parentElement?.getAttribute('data-date');
|
|
||||||
if (currentDate !== targetDate) {
|
|
||||||
this.moveAllDayToNewDate(targetDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup header mouseover detection for all-day conversion
|
|
||||||
this.setupHeaderMouseoverDetection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup header mouseover detection during drag
|
|
||||||
*/
|
|
||||||
private setupHeaderMouseoverDetection(): void {
|
|
||||||
document.addEventListener('mouseover', (event) => {
|
|
||||||
if (!this.draggedClone) return; // Only during active drag
|
|
||||||
|
|
||||||
const target = event.target as HTMLElement;
|
|
||||||
|
|
||||||
// Check if mouse is over a day header
|
|
||||||
let dayHeader = target.closest('swp-day-header') as HTMLElement;
|
|
||||||
if (dayHeader) {
|
|
||||||
const targetDate = dayHeader.dataset.date;
|
|
||||||
if (targetDate && this.draggedClone.tagName === 'SWP-EVENT') {
|
|
||||||
|
|
||||||
// Find the header renderer from the calendar header
|
|
||||||
const calendarHeader = dayHeader.closest('swp-calendar-header');
|
|
||||||
if (calendarHeader) {
|
|
||||||
// Emit header mouseover event like the original ColumnDetector did
|
|
||||||
eventBus.emit('header:mouseover', {
|
|
||||||
element: dayHeader,
|
|
||||||
targetDate: targetDate,
|
|
||||||
headerRenderer: this.getHeaderRenderer()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the header renderer instance for triggering addToAllDay
|
|
||||||
*/
|
|
||||||
private getHeaderRenderer(): any {
|
|
||||||
// For now, we'll create a simple object with the addToAllDay method
|
|
||||||
// This mimics what ColumnDetector had access to
|
|
||||||
return {
|
|
||||||
addToAllDay: (element: HTMLElement) => {
|
|
||||||
// Find the calendar header and call the HeaderRenderer's addToAllDay method
|
|
||||||
const calendarHeader = element.closest('swp-calendar-header') as HTMLElement;
|
|
||||||
if (calendarHeader) {
|
|
||||||
// Import and use HeaderRenderer directly
|
|
||||||
import('./HeaderRenderer').then(({ BaseHeaderRenderer }) => {
|
|
||||||
const headerRenderer = new BaseHeaderRenderer();
|
|
||||||
headerRenderer.addToAllDay(element);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get original event duration from data-duration attribute
|
* Get original event duration from data-duration attribute
|
||||||
*/
|
*/
|
||||||
|
|
@ -496,9 +421,10 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the all-day container
|
// Find the all-day container (should always exist now)
|
||||||
const allDayContainer = calendarHeader.querySelector('swp-allday-container') as HTMLElement;
|
const allDayContainer = calendarHeader.querySelector('swp-allday-container') as HTMLElement;
|
||||||
if (!allDayContainer) {
|
if (!allDayContainer) {
|
||||||
|
console.warn('All-day container not found - this should not happen');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,8 +432,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
allDayContainer.innerHTML = '';
|
allDayContainer.innerHTML = '';
|
||||||
|
|
||||||
if (allDayEvents.length === 0) {
|
if (allDayEvents.length === 0) {
|
||||||
// No events - just return
|
// No events - container exists but is empty and hidden
|
||||||
this.updateAllDayHeight(1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -579,9 +504,6 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
allDayContainer.appendChild(allDayEvent);
|
allDayContainer.appendChild(allDayEvent);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update height based on max row
|
|
||||||
this.updateAllDayHeight(maxRow);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -651,23 +573,6 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
return `${displayHour}:${minutes.toString().padStart(2, '0')} ${period}`;
|
return `${displayHour}:${minutes.toString().padStart(2, '0')} ${period}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update all-day row height and grid template based on number of rows
|
|
||||||
*/
|
|
||||||
private updateAllDayHeight(maxRows: number): void {
|
|
||||||
const root = document.documentElement;
|
|
||||||
const eventHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-event-height'));
|
|
||||||
const calculatedHeight = maxRows * eventHeight;
|
|
||||||
root.style.setProperty('--all-day-row-height', `${calculatedHeight}px`);
|
|
||||||
|
|
||||||
// Update grid-template-rows for all swp-allday-containers
|
|
||||||
const allDayContainers = document.querySelectorAll('swp-allday-container');
|
|
||||||
allDayContainers.forEach(container => {
|
|
||||||
const gridRows = `repeat(${maxRows}, var(--all-day-event-height))`;
|
|
||||||
(container as HTMLElement).style.gridTemplateRows = gridRows;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate grid column span for event
|
* Calculate grid column span for event
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure all-day containers exist - but don't create them initially, use lazy creation
|
* Ensure all-day containers exist - always create them during header rendering
|
||||||
*/
|
*/
|
||||||
ensureAllDayContainers(calendarHeader: HTMLElement): void {
|
ensureAllDayContainers(calendarHeader: HTMLElement): void {
|
||||||
// Do nothing initially - containers will be created when first needed
|
this.createAllDayMainStructure(calendarHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private animateHeaderExpansion(calendarHeader: HTMLElement): void {
|
private animateHeaderExpansion(calendarHeader: HTMLElement): void {
|
||||||
|
|
@ -163,6 +163,9 @@ export class DateHeaderRenderer extends BaseHeaderRenderer {
|
||||||
|
|
||||||
calendarHeader.appendChild(header);
|
calendarHeader.appendChild(header);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Always create all-day container after rendering headers
|
||||||
|
this.ensureAllDayContainers(calendarHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,5 +195,7 @@ export class ResourceHeaderRenderer extends BaseHeaderRenderer {
|
||||||
calendarHeader.appendChild(header);
|
calendarHeader.appendChild(header);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Always create all-day container after rendering headers
|
||||||
|
this.ensureAllDayContainers(calendarHeader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
--week-days: 7;
|
--week-days: 7;
|
||||||
--header-height: 80px;
|
--header-height: 80px;
|
||||||
--all-day-row-height: 0px; /* Default height for all-day events row */
|
--all-day-row-height: 0px; /* Default height for all-day events row */
|
||||||
--allday-event-height: 26px; /* Height of single all-day event including gaps */
|
--all-day-event-height: 26px; /* Height of single all-day event including gaps */
|
||||||
--stack-levels: 1; /* Number of stack levels for all-day events */
|
--stack-levels: 1; /* Number of stack levels for all-day events */
|
||||||
|
|
||||||
/* Time boundaries - Default fallback values */
|
/* Time boundaries - Default fallback values */
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ swp-time-grid::after {
|
||||||
swp-calendar-header {
|
swp-calendar-header {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
||||||
grid-template-rows: var(--header-height) var(--all-day-row-height); /* Row 1: header height, Row 2: all-day events height */
|
grid-template-rows: var(--header-height) auto; /* Row 1: header height, Row 2: auto for all-day events */
|
||||||
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width)); /* Dynamic width */
|
min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width)); /* Dynamic width */
|
||||||
background: var(--color-surface);
|
background: var(--color-surface);
|
||||||
border-bottom: 1px solid var(--color-border);
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
|
@ -273,14 +273,14 @@ swp-allday-container {
|
||||||
grid-row: 2; /* Second row of calendar header */
|
grid-row: 2; /* Second row of calendar header */
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr));
|
||||||
grid-template-rows: repeat(1, var(--allday-event-height, 26px)); /* Default to 1 row, dynamically updated by JS */
|
grid-template-rows: repeat(1, var(--all-day-event-height)); /* Default to 1 row, dynamically updated by JS */
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
/* Initially hidden - no CSS transitions, use Web Animations API */
|
/* Initially hidden - no CSS transitions, use Web Animations API */
|
||||||
height: 0;
|
height: var(--all-day-row-height);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue