This commit is contained in:
Janus C. H. Knudsen 2025-10-02 23:11:26 +02:00
parent 88702e574a
commit 89e8a3f7b2
6 changed files with 137 additions and 198 deletions

View file

@ -44,11 +44,7 @@ export class AllDayManager {
this.allDayEventRenderer = new AllDayEventRenderer();
// Sync CSS variable with TypeScript constant to ensure consistency
document.documentElement.style.setProperty(
'--single-row-height',
`${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`
);
document.documentElement.style.setProperty('--single-row-height', `${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`);
this.setupEventListeners();
}
@ -59,6 +55,9 @@ export class AllDayManager {
eventBus.on('drag:mouseenter-header', (event) => {
const payload = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail;
if (payload.draggedClone.hasAttribute('data-allday'))
return;
console.log('🔄 AllDayManager: Received drag:mouseenter-header', {
targetDate: payload.targetColumn,
originalElementId: payload.originalElement?.dataset?.eventId,
@ -75,33 +74,27 @@ export class AllDayManager {
originalElementId: originalElement?.dataset?.eventId
});
//this.checkAndAnimateAllDayHeight();
});
// Listen for drag operations on all-day events
eventBus.on('drag:start', (event) => {
const { draggedElement, draggedClone, mouseOffset } = (event as CustomEvent<DragStartEventPayload>).detail;
let payload: DragStartEventPayload = (event as CustomEvent<DragStartEventPayload>).detail;
// Check if this is an all-day event by checking if it's in all-day container
const isAllDayEvent = draggedElement.closest('swp-allday-container');
if (!isAllDayEvent) return; // Not an all-day event
if (!payload.draggedClone?.hasAttribute('data-allday')) {
return;
}
const eventId = draggedElement.dataset.eventId;
console.log('🎯 AllDayManager: Starting drag for all-day event', { eventId });
this.handleDragStart(draggedElement, eventId || '', mouseOffset);
this.allDayEventRenderer.handleDragStart(payload);
});
eventBus.on('drag:column-change', (event) => {
const { originalElement: draggedElement, draggedClone, mousePosition } = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
let payload: DragColumnChangeEventPayload = (event as CustomEvent<DragColumnChangeEventPayload>).detail;
if (draggedClone == null)
if (!payload.draggedClone?.hasAttribute('data-allday')) {
return;
if (!draggedClone.hasAttribute('data-allday')) {
return; // This is not an all-day event
}
this.handleColumnChange(draggedClone, mousePosition);
this.handleColumnChange(payload);
});
eventBus.on('drag:end', (event) => {
@ -320,25 +313,13 @@ export class AllDayManager {
*/
private handleConvertToAllDay(payload: DragMouseEnterHeaderEventPayload): void {
if (payload.draggedClone?.dataset == null)
console.error("payload.cloneElement.dataset.eventId is null");
console.log('🔄 AllDayManager: Converting to all-day (row 1 only during drag)', {
eventId: payload.draggedClone.dataset.eventId,
targetDate: payload.targetColumn
});
// Get all-day container, request creation if needed
let allDayContainer = this.getAllDayContainer();
payload.draggedClone.removeAttribute('style');
payload.draggedClone.style.gridRow = '1';
payload.draggedClone.style.gridColumn = payload.targetColumn.index.toString();
payload.draggedClone.dataset.allday = 'true'; // Set the all-day attribute for filtering
payload.draggedClone.dataset.allday = 'true';
// Add to container
allDayContainer?.appendChild(payload.draggedClone);
ColumnDetectionUtils.updateColumnBoundsCache();
@ -346,63 +327,36 @@ export class AllDayManager {
}
/**
* Handle drag start for all-day events
*/
private handleDragStart(originalElement: HTMLElement, eventId: string, mouseOffset: DragOffset): void {
// Create clone
const clone = originalElement.cloneNode(true) as HTMLElement;
clone.dataset.eventId = `clone-${eventId}`;
// Get container
const container = this.getAllDayContainer();
if (!container) return;
// Add clone to container
container.appendChild(clone);
// Copy positioning from original
clone.style.gridColumn = originalElement.style.gridColumn;
clone.style.gridRow = originalElement.style.gridRow;
// Add dragging style
clone.classList.add('dragging');
clone.style.zIndex = '1000';
clone.style.cursor = 'grabbing';
// Make original semi-transparent
originalElement.style.opacity = '0.3';
console.log('✅ AllDayManager: Created drag clone for all-day event', {
eventId,
cloneId: clone.dataset.eventId,
gridColumn: clone.style.gridColumn,
gridRow: clone.style.gridRow
});
}
/**
* Handle drag move for all-day events - SPECIALIZED FOR ALL-DAY CONTAINER
*/
private handleColumnChange(dragClone: HTMLElement, mousePosition: MousePosition): void {
// Get the all-day container to understand its grid structure
const allDayContainer = this.getAllDayContainer();
private handleColumnChange(dragColumnChangeEventPayload: DragColumnChangeEventPayload): void {
let allDayContainer = this.getAllDayContainer();
if (!allDayContainer) return;
// Calculate target column using ColumnDetectionUtils
const targetColumn = ColumnDetectionUtils.getColumnBounds(mousePosition);
let targetColumn = ColumnDetectionUtils.getColumnBounds(dragColumnChangeEventPayload.mousePosition);
if (targetColumn == null)
return;
if (!dragColumnChangeEventPayload.draggedClone)
return;
// Update clone position - ALWAYS keep in row 1 during drag
// Use simple grid positioning that matches all-day container structure
dragClone.style.gridColumn = targetColumn.index.toString();
//dragClone.style.gridRow = '1'; // Force row 1 during drag
dragClone.style.gridArea = `1 / ${targetColumn.index} / 2 / ${targetColumn.index + 1}`;
dragColumnChangeEventPayload.draggedClone.style.gridColumn = targetColumn.index.toString();
//dragColumnChangeEventPayload.draggedClone.style.gridRow = dragColumnChangeEventPayload.draggedClone.style.gridRow; // Bevar nuværende row
}
private fadeOutAndRemove(element: HTMLElement): void {
element.style.transition = 'opacity 0.3s ease-out';
element.style.opacity = '0';
setTimeout(() => {
element.remove();
}, 300);
}
/**
* Handle drag end for all-day events - WITH DIFFERENTIAL UPDATES
*/
@ -414,6 +368,7 @@ export class AllDayManager {
// 2. Normalize clone ID
dragEndEvent.draggedClone.dataset.eventId = dragEndEvent.draggedClone.dataset.eventId?.replace('clone-', '');
// 3. Create temporary array with existing events + the dropped event
let eventId = dragEndEvent.draggedClone.dataset.eventId;
let eventDate = dragEndEvent.finalPosition.column?.date;
@ -423,6 +378,7 @@ export class AllDayManager {
return;
const droppedEvent: CalendarEvent = {
id: eventId,
title: dragEndEvent.draggedClone.dataset.title || '',
@ -434,27 +390,29 @@ export class AllDayManager {
};
// Use current events + dropped event for calculation
const tempEvents = [...this.currentAllDayEvents, droppedEvent];
const tempEvents = [...this.currentAllDayEvents, droppedEvent].except(dragEndEvent.originalElement);
// 4. Calculate new layouts for ALL events
this.newLayouts = this.calculateAllDayEventsLayout(tempEvents, this.currentWeekDates);
// 5. Apply differential updates - only update events that changed
let changedCount = 0;
let container = this.getAllDayContainer();
this.newLayouts.forEach((layout) => {
// Find current layout for this event
let currentLayout = this.currentLayouts.find(old => old.calenderEvent.id === layout.calenderEvent.id);
if (currentLayout?.gridArea !== layout.gridArea) {
changedCount++;
const element = dragEndEvent.draggedClone;
let element = container?.querySelector(`[data-event-id="${layout.calenderEvent.id}"]`) as HTMLElement;
if (element) {
// Add transition class for smooth animation
element.classList.add('transitioning');
element.style.gridArea = layout.gridArea;
element.style.gridRow = layout.row.toString();
element.style.gridColumn = `${layout.startColumn} / ${layout.endColumn + 1}`;
if (layout.row > ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS)
if (!this.isExpanded)
element.classList.add('max-event-overflow-hide');
@ -477,7 +435,8 @@ export class AllDayManager {
dragEndEvent.draggedClone.style.opacity = '';
// 7. Restore original element opacity
dragEndEvent.originalElement.remove(); //TODO: this should be an event that only fade and remove if confirmed dragdrop
//dragEndEvent.originalElement.remove(); //TODO: this should be an event that only fade and remove if confirmed dragdrop
this.fadeOutAndRemove(dragEndEvent.originalElement);
// 8. Check if height adjustment is needed
this.checkAndAnimateAllDayHeight();

View file

@ -211,31 +211,32 @@ export class DragDropManager {
// Continue with normal drag behavior only if drag has started
if (this.isDragStarted && this.draggedElement && this.draggedClone) {
const deltaY = Math.abs(currentPosition.y - this.lastLoggedPosition.y);
if (!this.draggedElement.hasAttribute("data-allday")) {
const deltaY = Math.abs(currentPosition.y - this.lastLoggedPosition.y);
// Check for snap interval vertical movement (normal drag behavior)
if (deltaY >= this.snapDistancePx) {
this.lastLoggedPosition = currentPosition;
// Check for snap interval vertical movement (normal drag behavior)
if (deltaY >= this.snapDistancePx) {
this.lastLoggedPosition = currentPosition;
// Consolidated position calculations with snapping for normal drag
const positionData = this.calculateDragPosition(currentPosition);
// Consolidated position calculations with snapping for normal drag
const positionData = this.calculateDragPosition(currentPosition);
// Emit drag move event with snapped position (normal behavior)
const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement,
draggedClone: this.draggedClone,
mousePosition: currentPosition,
snappedY: positionData.snappedY,
columnBounds: positionData.column,
mouseOffset: this.mouseOffset
};
this.eventBus.emit('drag:move', dragMovePayload);
// Emit drag move event with snapped position (normal behavior)
const dragMovePayload: DragMoveEventPayload = {
draggedElement: this.draggedElement,
draggedClone: this.draggedClone,
mousePosition: currentPosition,
snappedY: positionData.snappedY,
columnBounds: positionData.column,
mouseOffset: this.mouseOffset
};
this.eventBus.emit('drag:move', dragMovePayload);
}
// Check for auto-scroll
this.checkAutoScroll(currentPosition);
}
// Check for auto-scroll
this.checkAutoScroll(currentPosition);
// Check for column change using cached data
const newColumn = ColumnDetectionUtils.getColumnBounds(currentPosition);
if (newColumn == null)
return;
@ -294,8 +295,8 @@ export class DragDropManager {
target: dropTarget
};
this.eventBus.emit('drag:end', dragEndPayload);
this.draggedElement = null;
} else {