wip
This commit is contained in:
parent
88702e574a
commit
89e8a3f7b2
6 changed files with 137 additions and 198 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
import { CalendarMode } from '../types/CalendarTypes';
|
import { CalendarMode } from '../types/CalendarTypes';
|
||||||
import { HeaderRenderer, DateHeaderRenderer, ResourceHeaderRenderer } from '../renderers/HeaderRenderer';
|
import { HeaderRenderer, DateHeaderRenderer, ResourceHeaderRenderer } from '../renderers/HeaderRenderer';
|
||||||
import { ColumnRenderer, DateColumnRenderer, ResourceColumnRenderer } from '../renderers/ColumnRenderer';
|
import { ColumnRenderer, DateColumnRenderer, ResourceColumnRenderer } from '../renderers/ColumnRenderer';
|
||||||
import { EventRendererStrategy, DateEventRenderer, ResourceEventRenderer } from '../renderers/EventRenderer';
|
import { EventRendererStrategy, DateEventRenderer } from '../renderers/EventRenderer';
|
||||||
import { calendarConfig } from '../core/CalendarConfig';
|
import { calendarConfig } from '../core/CalendarConfig';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,11 +37,11 @@ export class CalendarTypeFactory {
|
||||||
eventRenderer: new DateEventRenderer()
|
eventRenderer: new DateEventRenderer()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerRenderers('resource', {
|
//this.registerRenderers('resource', {
|
||||||
headerRenderer: new ResourceHeaderRenderer(),
|
// headerRenderer: new ResourceHeaderRenderer(),
|
||||||
columnRenderer: new ResourceColumnRenderer(),
|
// columnRenderer: new ResourceColumnRenderer(),
|
||||||
eventRenderer: new ResourceEventRenderer()
|
// eventRenderer: new ResourceEventRenderer()
|
||||||
});
|
//});
|
||||||
|
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,7 @@ export class AllDayManager {
|
||||||
this.allDayEventRenderer = new AllDayEventRenderer();
|
this.allDayEventRenderer = new AllDayEventRenderer();
|
||||||
|
|
||||||
// Sync CSS variable with TypeScript constant to ensure consistency
|
// Sync CSS variable with TypeScript constant to ensure consistency
|
||||||
document.documentElement.style.setProperty(
|
document.documentElement.style.setProperty('--single-row-height', `${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`);
|
||||||
'--single-row-height',
|
|
||||||
`${ALL_DAY_CONSTANTS.EVENT_HEIGHT}px`
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +55,9 @@ export class AllDayManager {
|
||||||
eventBus.on('drag:mouseenter-header', (event) => {
|
eventBus.on('drag:mouseenter-header', (event) => {
|
||||||
const payload = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail;
|
const payload = (event as CustomEvent<DragMouseEnterHeaderEventPayload>).detail;
|
||||||
|
|
||||||
|
if (payload.draggedClone.hasAttribute('data-allday'))
|
||||||
|
return;
|
||||||
|
|
||||||
console.log('🔄 AllDayManager: Received drag:mouseenter-header', {
|
console.log('🔄 AllDayManager: Received drag:mouseenter-header', {
|
||||||
targetDate: payload.targetColumn,
|
targetDate: payload.targetColumn,
|
||||||
originalElementId: payload.originalElement?.dataset?.eventId,
|
originalElementId: payload.originalElement?.dataset?.eventId,
|
||||||
|
|
@ -75,33 +74,27 @@ export class AllDayManager {
|
||||||
originalElementId: originalElement?.dataset?.eventId
|
originalElementId: originalElement?.dataset?.eventId
|
||||||
});
|
});
|
||||||
|
|
||||||
//this.checkAndAnimateAllDayHeight();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for drag operations on all-day events
|
// Listen for drag operations on all-day events
|
||||||
eventBus.on('drag:start', (event) => {
|
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
|
if (!payload.draggedClone?.hasAttribute('data-allday')) {
|
||||||
const isAllDayEvent = draggedElement.closest('swp-allday-container');
|
return;
|
||||||
if (!isAllDayEvent) return; // Not an all-day event
|
}
|
||||||
|
|
||||||
const eventId = draggedElement.dataset.eventId;
|
this.allDayEventRenderer.handleDragStart(payload);
|
||||||
console.log('🎯 AllDayManager: Starting drag for all-day event', { eventId });
|
|
||||||
this.handleDragStart(draggedElement, eventId || '', mouseOffset);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
eventBus.on('drag:column-change', (event) => {
|
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;
|
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) => {
|
eventBus.on('drag:end', (event) => {
|
||||||
|
|
@ -320,25 +313,13 @@ export class AllDayManager {
|
||||||
*/
|
*/
|
||||||
private handleConvertToAllDay(payload: DragMouseEnterHeaderEventPayload): void {
|
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();
|
let allDayContainer = this.getAllDayContainer();
|
||||||
|
|
||||||
|
|
||||||
payload.draggedClone.removeAttribute('style');
|
payload.draggedClone.removeAttribute('style');
|
||||||
payload.draggedClone.style.gridRow = '1';
|
payload.draggedClone.style.gridRow = '1';
|
||||||
payload.draggedClone.style.gridColumn = payload.targetColumn.index.toString();
|
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);
|
allDayContainer?.appendChild(payload.draggedClone);
|
||||||
|
|
||||||
ColumnDetectionUtils.updateColumnBoundsCache();
|
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
|
* Handle drag move for all-day events - SPECIALIZED FOR ALL-DAY CONTAINER
|
||||||
*/
|
*/
|
||||||
private handleColumnChange(dragClone: HTMLElement, mousePosition: MousePosition): void {
|
private handleColumnChange(dragColumnChangeEventPayload: DragColumnChangeEventPayload): void {
|
||||||
// Get the all-day container to understand its grid structure
|
|
||||||
const allDayContainer = this.getAllDayContainer();
|
let allDayContainer = this.getAllDayContainer();
|
||||||
if (!allDayContainer) return;
|
if (!allDayContainer) return;
|
||||||
|
|
||||||
// Calculate target column using ColumnDetectionUtils
|
let targetColumn = ColumnDetectionUtils.getColumnBounds(dragColumnChangeEventPayload.mousePosition);
|
||||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(mousePosition);
|
|
||||||
|
|
||||||
if (targetColumn == null)
|
if (targetColumn == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!dragColumnChangeEventPayload.draggedClone)
|
||||||
|
return;
|
||||||
|
|
||||||
// Update clone position - ALWAYS keep in row 1 during drag
|
// Update clone position - ALWAYS keep in row 1 during drag
|
||||||
// Use simple grid positioning that matches all-day container structure
|
// Use simple grid positioning that matches all-day container structure
|
||||||
dragClone.style.gridColumn = targetColumn.index.toString();
|
dragColumnChangeEventPayload.draggedClone.style.gridColumn = targetColumn.index.toString();
|
||||||
//dragClone.style.gridRow = '1'; // Force row 1 during drag
|
//dragColumnChangeEventPayload.draggedClone.style.gridRow = dragColumnChangeEventPayload.draggedClone.style.gridRow; // Bevar nuværende row
|
||||||
dragClone.style.gridArea = `1 / ${targetColumn.index} / 2 / ${targetColumn.index + 1}`;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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
|
* Handle drag end for all-day events - WITH DIFFERENTIAL UPDATES
|
||||||
*/
|
*/
|
||||||
|
|
@ -414,6 +368,7 @@ export class AllDayManager {
|
||||||
// 2. Normalize clone ID
|
// 2. Normalize clone ID
|
||||||
dragEndEvent.draggedClone.dataset.eventId = dragEndEvent.draggedClone.dataset.eventId?.replace('clone-', '');
|
dragEndEvent.draggedClone.dataset.eventId = dragEndEvent.draggedClone.dataset.eventId?.replace('clone-', '');
|
||||||
|
|
||||||
|
|
||||||
// 3. Create temporary array with existing events + the dropped event
|
// 3. Create temporary array with existing events + the dropped event
|
||||||
let eventId = dragEndEvent.draggedClone.dataset.eventId;
|
let eventId = dragEndEvent.draggedClone.dataset.eventId;
|
||||||
let eventDate = dragEndEvent.finalPosition.column?.date;
|
let eventDate = dragEndEvent.finalPosition.column?.date;
|
||||||
|
|
@ -423,6 +378,7 @@ export class AllDayManager {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const droppedEvent: CalendarEvent = {
|
const droppedEvent: CalendarEvent = {
|
||||||
id: eventId,
|
id: eventId,
|
||||||
title: dragEndEvent.draggedClone.dataset.title || '',
|
title: dragEndEvent.draggedClone.dataset.title || '',
|
||||||
|
|
@ -434,27 +390,29 @@ export class AllDayManager {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use current events + dropped event for calculation
|
// 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
|
// 4. Calculate new layouts for ALL events
|
||||||
this.newLayouts = this.calculateAllDayEventsLayout(tempEvents, this.currentWeekDates);
|
this.newLayouts = this.calculateAllDayEventsLayout(tempEvents, this.currentWeekDates);
|
||||||
|
|
||||||
// 5. Apply differential updates - only update events that changed
|
// 5. Apply differential updates - only update events that changed
|
||||||
let changedCount = 0;
|
let changedCount = 0;
|
||||||
|
let container = this.getAllDayContainer();
|
||||||
this.newLayouts.forEach((layout) => {
|
this.newLayouts.forEach((layout) => {
|
||||||
// Find current layout for this event
|
// Find current layout for this event
|
||||||
let currentLayout = this.currentLayouts.find(old => old.calenderEvent.id === layout.calenderEvent.id);
|
let currentLayout = this.currentLayouts.find(old => old.calenderEvent.id === layout.calenderEvent.id);
|
||||||
|
|
||||||
if (currentLayout?.gridArea !== layout.gridArea) {
|
if (currentLayout?.gridArea !== layout.gridArea) {
|
||||||
changedCount++;
|
changedCount++;
|
||||||
const element = dragEndEvent.draggedClone;
|
let element = container?.querySelector(`[data-event-id="${layout.calenderEvent.id}"]`) as HTMLElement;
|
||||||
if (element) {
|
if (element) {
|
||||||
// Add transition class for smooth animation
|
|
||||||
element.classList.add('transitioning');
|
element.classList.add('transitioning');
|
||||||
element.style.gridArea = layout.gridArea;
|
element.style.gridArea = layout.gridArea;
|
||||||
element.style.gridRow = layout.row.toString();
|
element.style.gridRow = layout.row.toString();
|
||||||
element.style.gridColumn = `${layout.startColumn} / ${layout.endColumn + 1}`;
|
element.style.gridColumn = `${layout.startColumn} / ${layout.endColumn + 1}`;
|
||||||
|
|
||||||
|
|
||||||
if (layout.row > ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS)
|
if (layout.row > ALL_DAY_CONSTANTS.MAX_COLLAPSED_ROWS)
|
||||||
if (!this.isExpanded)
|
if (!this.isExpanded)
|
||||||
element.classList.add('max-event-overflow-hide');
|
element.classList.add('max-event-overflow-hide');
|
||||||
|
|
@ -477,7 +435,8 @@ export class AllDayManager {
|
||||||
dragEndEvent.draggedClone.style.opacity = '';
|
dragEndEvent.draggedClone.style.opacity = '';
|
||||||
|
|
||||||
// 7. Restore original element 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
|
// 8. Check if height adjustment is needed
|
||||||
this.checkAndAnimateAllDayHeight();
|
this.checkAndAnimateAllDayHeight();
|
||||||
|
|
|
||||||
|
|
@ -211,31 +211,32 @@ export class DragDropManager {
|
||||||
|
|
||||||
// Continue with normal drag behavior only if drag has started
|
// Continue with normal drag behavior only if drag has started
|
||||||
if (this.isDragStarted && this.draggedElement && this.draggedClone) {
|
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)
|
// Check for snap interval vertical movement (normal drag behavior)
|
||||||
if (deltaY >= this.snapDistancePx) {
|
if (deltaY >= this.snapDistancePx) {
|
||||||
this.lastLoggedPosition = currentPosition;
|
this.lastLoggedPosition = currentPosition;
|
||||||
|
|
||||||
// Consolidated position calculations with snapping for normal drag
|
// Consolidated position calculations with snapping for normal drag
|
||||||
const positionData = this.calculateDragPosition(currentPosition);
|
const positionData = this.calculateDragPosition(currentPosition);
|
||||||
|
|
||||||
// Emit drag move event with snapped position (normal behavior)
|
// Emit drag move event with snapped position (normal behavior)
|
||||||
const dragMovePayload: DragMoveEventPayload = {
|
const dragMovePayload: DragMoveEventPayload = {
|
||||||
draggedElement: this.draggedElement,
|
draggedElement: this.draggedElement,
|
||||||
draggedClone: this.draggedClone,
|
draggedClone: this.draggedClone,
|
||||||
mousePosition: currentPosition,
|
mousePosition: currentPosition,
|
||||||
snappedY: positionData.snappedY,
|
snappedY: positionData.snappedY,
|
||||||
columnBounds: positionData.column,
|
columnBounds: positionData.column,
|
||||||
mouseOffset: this.mouseOffset
|
mouseOffset: this.mouseOffset
|
||||||
};
|
};
|
||||||
this.eventBus.emit('drag:move', dragMovePayload);
|
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);
|
const newColumn = ColumnDetectionUtils.getColumnBounds(currentPosition);
|
||||||
if (newColumn == null)
|
if (newColumn == null)
|
||||||
return;
|
return;
|
||||||
|
|
@ -294,8 +295,8 @@ export class DragDropManager {
|
||||||
target: dropTarget
|
target: dropTarget
|
||||||
};
|
};
|
||||||
this.eventBus.emit('drag:end', dragEndPayload);
|
this.eventBus.emit('drag:end', dragEndPayload);
|
||||||
|
|
||||||
|
|
||||||
this.draggedElement = null;
|
this.draggedElement = null;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,20 @@ import { SwpAllDayEventElement } from '../elements/SwpEventElement';
|
||||||
import { EventLayout } from '../utils/AllDayLayoutEngine';
|
import { EventLayout } from '../utils/AllDayLayoutEngine';
|
||||||
import { ColumnBounds } from '../utils/ColumnDetectionUtils';
|
import { ColumnBounds } from '../utils/ColumnDetectionUtils';
|
||||||
import { EventManager } from '../managers/EventManager';
|
import { EventManager } from '../managers/EventManager';
|
||||||
/**
|
import { DragStartEventPayload } from '../types/EventTypes';
|
||||||
* AllDayEventRenderer - Simple rendering of all-day events
|
import { EventRendererStrategy } from './EventRenderer';
|
||||||
* Handles adding and removing all-day events from the header container
|
|
||||||
* NOTE: Layout calculation is now handled by AllDayManager
|
|
||||||
*/
|
|
||||||
export class AllDayEventRenderer {
|
export class AllDayEventRenderer {
|
||||||
|
|
||||||
private container: HTMLElement | null = null;
|
private container: HTMLElement | null = null;
|
||||||
|
private originalEvent: HTMLElement | null = null;
|
||||||
|
private draggedClone: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.getContainer();
|
this.getContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or cache all-day container, create if it doesn't exist - SIMPLIFIED (no ghost columns)
|
|
||||||
*/
|
|
||||||
private getContainer(): HTMLElement | null {
|
private getContainer(): HTMLElement | null {
|
||||||
|
|
||||||
const header = document.querySelector('swp-calendar-header');
|
const header = document.querySelector('swp-calendar-header');
|
||||||
|
|
@ -27,14 +26,45 @@ export class AllDayEventRenderer {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
this.container = document.createElement('swp-allday-container');
|
this.container = document.createElement('swp-allday-container');
|
||||||
header.appendChild(this.container);
|
header.appendChild(this.container);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.container;
|
return this.container;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMOVED: createGhostColumns() method - no longer needed!
|
|
||||||
|
private getAllDayContainer(): HTMLElement | null {
|
||||||
|
return document.querySelector('swp-calendar-header swp-allday-container');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Handle drag start for all-day events
|
||||||
|
*/
|
||||||
|
public handleDragStart(payload: DragStartEventPayload): void {
|
||||||
|
|
||||||
|
this.originalEvent = payload.draggedElement;;
|
||||||
|
this.draggedClone = payload.draggedClone;
|
||||||
|
|
||||||
|
if (this.draggedClone) {
|
||||||
|
|
||||||
|
const container = this.getAllDayContainer();
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
this.draggedClone.style.gridColumn = this.originalEvent.style.gridColumn;
|
||||||
|
this.draggedClone.style.gridRow = this.originalEvent.style.gridRow;
|
||||||
|
console.log('handleDragStart:this.draggedClone', this.draggedClone);
|
||||||
|
container.appendChild(this.draggedClone);
|
||||||
|
|
||||||
|
// Add dragging style
|
||||||
|
this.draggedClone.classList.add('dragging');
|
||||||
|
this.draggedClone.style.zIndex = '1000';
|
||||||
|
this.draggedClone.style.cursor = 'grabbing';
|
||||||
|
|
||||||
|
// Make original semi-transparent
|
||||||
|
this.originalEvent.style.opacity = '0.3';
|
||||||
|
this.originalEvent.style.userSelect = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render an all-day event with pre-calculated layout
|
* Render an all-day event with pre-calculated layout
|
||||||
|
|
@ -77,28 +107,14 @@ export class AllDayEventRenderer {
|
||||||
* Render all-day events for specific period using AllDayEventRenderer
|
* Render all-day events for specific period using AllDayEventRenderer
|
||||||
*/
|
*/
|
||||||
public renderAllDayEventsForPeriod(eventLayouts: EventLayout[]): void {
|
public renderAllDayEventsForPeriod(eventLayouts: EventLayout[]): void {
|
||||||
// Get events from EventManager for the period
|
|
||||||
// const events = this.eventManager.getEventsForPeriod(startDate, endDate);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Clear existing all-day events first
|
|
||||||
this.clearAllDayEvents();
|
this.clearAllDayEvents();
|
||||||
|
|
||||||
// Get actual visible dates from DOM headers instead of generating them
|
|
||||||
|
|
||||||
// const layouts = this.allDayManager.initAllDayEventsLayout(allDayEvents, weekDates);
|
|
||||||
|
|
||||||
// Render each all-day event with pre-calculated layout
|
|
||||||
eventLayouts.forEach(layout => {
|
eventLayouts.forEach(layout => {
|
||||||
this.renderAllDayEventWithLayout(layout.calenderEvent, layout);
|
this.renderAllDayEventWithLayout(layout.calenderEvent, layout);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Clear only all-day events
|
|
||||||
*/
|
|
||||||
private clearAllDayEvents(): void {
|
private clearAllDayEvents(): void {
|
||||||
const allDayContainer = document.querySelector('swp-allday-container');
|
const allDayContainer = document.querySelector('swp-allday-container');
|
||||||
if (allDayContainer) {
|
if (allDayContainer) {
|
||||||
|
|
|
||||||
|
|
@ -26,25 +26,32 @@ export interface EventRendererStrategy {
|
||||||
handleColumnChange?(payload: DragColumnChangeEventPayload): void;
|
handleColumnChange?(payload: DragColumnChangeEventPayload): void;
|
||||||
handleNavigationCompleted?(): void;
|
handleNavigationCompleted?(): void;
|
||||||
}
|
}
|
||||||
|
// Abstract methods that subclasses must implement
|
||||||
|
// private getColumns(container: HTMLElement): HTMLElement[];
|
||||||
|
// private getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for event renderers with common functionality
|
* Date-based event renderer
|
||||||
*/
|
*/
|
||||||
export abstract class BaseEventRenderer implements EventRendererStrategy {
|
export class DateEventRenderer implements EventRendererStrategy {
|
||||||
protected dateCalculator: DateCalculator;
|
|
||||||
|
|
||||||
// Drag and drop state
|
|
||||||
private draggedClone: HTMLElement | null = null;
|
|
||||||
private originalEvent: HTMLElement | null = null;
|
|
||||||
|
|
||||||
// Resize manager
|
|
||||||
|
|
||||||
constructor(dateCalculator?: DateCalculator) {
|
constructor(dateCalculator?: DateCalculator) {
|
||||||
|
|
||||||
if (!dateCalculator) {
|
if (!dateCalculator) {
|
||||||
DateCalculator.initialize(calendarConfig);
|
DateCalculator.initialize(calendarConfig);
|
||||||
}
|
}
|
||||||
this.dateCalculator = dateCalculator || new DateCalculator();
|
this.dateCalculator = dateCalculator || new DateCalculator();
|
||||||
|
|
||||||
|
|
||||||
|
this.setupDragEventListeners();
|
||||||
}
|
}
|
||||||
|
private dateCalculator: DateCalculator;
|
||||||
|
|
||||||
|
private draggedClone: HTMLElement | null = null;
|
||||||
|
private originalEvent: HTMLElement | null = null;
|
||||||
|
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// NEW OVERLAP DETECTION SYSTEM
|
// NEW OVERLAP DETECTION SYSTEM
|
||||||
|
|
@ -96,10 +103,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply common drag styling to an element
|
|
||||||
*/
|
|
||||||
private applyDragStyling(element: HTMLElement): void {
|
private applyDragStyling(element: HTMLElement): void {
|
||||||
element.classList.add('dragging');
|
element.classList.add('dragging');
|
||||||
}
|
}
|
||||||
|
|
@ -127,8 +131,8 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
// Snap to interval
|
// Snap to interval
|
||||||
const snappedStartMinutes = Math.round(actualStartMinutes / snapInterval) * snapInterval;
|
const snappedStartMinutes = Math.round(actualStartMinutes / snapInterval) * snapInterval;
|
||||||
|
|
||||||
|
|
||||||
if(!clone.dataset.originalDuration)
|
if (!clone.dataset.originalDuration)
|
||||||
throw new DOMException("missing clone.dataset.originalDuration")
|
throw new DOMException("missing clone.dataset.originalDuration")
|
||||||
|
|
||||||
const endTotalMinutes = snappedStartMinutes + parseInt(clone.dataset.originalDuration);
|
const endTotalMinutes = snappedStartMinutes + parseInt(clone.dataset.originalDuration);
|
||||||
|
|
@ -153,7 +157,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
this.draggedClone = payload.draggedClone;
|
this.draggedClone = payload.draggedClone;
|
||||||
|
|
||||||
if (this.draggedClone) {
|
if (this.draggedClone) {
|
||||||
// Apply drag styling
|
// Apply drag styling
|
||||||
this.applyDragStyling(this.draggedClone);
|
this.applyDragStyling(this.draggedClone);
|
||||||
|
|
||||||
// Add to current column's events layer (not directly to column)
|
// Add to current column's events layer (not directly to column)
|
||||||
|
|
@ -296,7 +300,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
|
|
||||||
// Fade out original
|
// Fade out original
|
||||||
// TODO: this should be changed into a subscriber which only after a succesful placement is fired, not just mouseup as this can remove elements that are not placed.
|
// TODO: this should be changed into a subscriber which only after a succesful placement is fired, not just mouseup as this can remove elements that are not placed.
|
||||||
this.fadeOutAndRemove(originalElement);
|
this.fadeOutAndRemove(originalElement);
|
||||||
|
|
||||||
// Remove clone prefix and normalize clone to be a regular event
|
// Remove clone prefix and normalize clone to be a regular event
|
||||||
const cloneId = draggedClone.dataset.eventId;
|
const cloneId = draggedClone.dataset.eventId;
|
||||||
|
|
@ -452,17 +456,14 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abstract methods that subclasses must implement
|
|
||||||
protected abstract getColumns(container: HTMLElement): HTMLElement[];
|
|
||||||
protected abstract getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[];
|
|
||||||
|
|
||||||
|
|
||||||
protected renderEvent(event: CalendarEvent): HTMLElement {
|
private renderEvent(event: CalendarEvent): HTMLElement {
|
||||||
const swpEvent = SwpEventElement.fromCalendarEvent(event);
|
const swpEvent = SwpEventElement.fromCalendarEvent(event);
|
||||||
const eventElement = swpEvent.getElement();
|
const eventElement = swpEvent.getElement();
|
||||||
|
|
||||||
// Setup resize handles on first mouseover only
|
// Setup resize handles on first mouseover only
|
||||||
eventElement.addEventListener('mouseover', () => {
|
eventElement.addEventListener('mouseover', () => { // TODO: This is not the correct way... we should not add eventlistener on every event
|
||||||
if (eventElement.dataset.hasResizeHandlers !== 'true') {
|
if (eventElement.dataset.hasResizeHandlers !== 'true') {
|
||||||
eventElement.dataset.hasResizeHandlers = 'true';
|
eventElement.dataset.hasResizeHandlers = 'true';
|
||||||
}
|
}
|
||||||
|
|
@ -544,16 +545,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
|
||||||
element.style.minWidth = '50px';
|
element.style.minWidth = '50px';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date-based event renderer
|
|
||||||
*/
|
|
||||||
export class DateEventRenderer extends BaseEventRenderer {
|
|
||||||
constructor(dateCalculator?: DateCalculator) {
|
|
||||||
super(dateCalculator);
|
|
||||||
this.setupDragEventListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup drag event listeners - placeholder method
|
* Setup drag event listeners - placeholder method
|
||||||
|
|
@ -585,32 +577,3 @@ export class DateEventRenderer extends BaseEventRenderer {
|
||||||
return columnEvents;
|
return columnEvents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resource-based event renderer
|
|
||||||
*/
|
|
||||||
export class ResourceEventRenderer extends BaseEventRenderer {
|
|
||||||
protected getColumns(container: HTMLElement): HTMLElement[] {
|
|
||||||
const columns = container.querySelectorAll('swp-resource-column');
|
|
||||||
return Array.from(columns) as HTMLElement[];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getEventsForColumn(column: HTMLElement, events: CalendarEvent[]): CalendarEvent[] {
|
|
||||||
const resourceName = column.dataset.resource;
|
|
||||||
if (!resourceName) return [];
|
|
||||||
|
|
||||||
const columnEvents = events.filter(event => {
|
|
||||||
return event.resource?.name === resourceName;
|
|
||||||
});
|
|
||||||
|
|
||||||
return columnEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================
|
|
||||||
// NEW OVERLAP DETECTION SYSTEM
|
|
||||||
// All new functions prefixed with new_
|
|
||||||
// ============================================
|
|
||||||
|
|
||||||
protected overlapDetector = new OverlapDetector();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -142,29 +142,29 @@ export class EventRenderingService {
|
||||||
* Setup all drag event listeners - moved from EventRenderer for better separation of concerns
|
* Setup all drag event listeners - moved from EventRenderer for better separation of concerns
|
||||||
*/
|
*/
|
||||||
private setupDragEventListeners(): void {
|
private setupDragEventListeners(): void {
|
||||||
// Handle drag start
|
|
||||||
this.eventBus.on('drag:start', (event: Event) => {
|
this.eventBus.on('drag:start', (event: Event) => {
|
||||||
const dragStartPayload = (event as CustomEvent<DragStartEventPayload>).detail;
|
const dragStartPayload = (event as CustomEvent<DragStartEventPayload>).detail;
|
||||||
// Use the draggedElement directly - no need for DOM query
|
|
||||||
|
if (dragStartPayload.draggedElement.hasAttribute('data-allday')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (dragStartPayload.draggedElement && this.strategy.handleDragStart && dragStartPayload.columnBounds) {
|
if (dragStartPayload.draggedElement && this.strategy.handleDragStart && dragStartPayload.columnBounds) {
|
||||||
this.strategy.handleDragStart(dragStartPayload);
|
this.strategy.handleDragStart(dragStartPayload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle drag move
|
|
||||||
this.eventBus.on('drag:move', (event: Event) => {
|
this.eventBus.on('drag:move', (event: Event) => {
|
||||||
let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail;
|
let dragEvent = (event as CustomEvent<DragMoveEventPayload>).detail;
|
||||||
|
|
||||||
// Filter: Only handle events WITHOUT data-allday attribute (normal timed events)
|
|
||||||
if (dragEvent.draggedElement.hasAttribute('data-allday')) {
|
if (dragEvent.draggedElement.hasAttribute('data-allday')) {
|
||||||
return; // This is an all-day event, let AllDayManager handle it
|
return;
|
||||||
}
|
}
|
||||||
if (this.strategy.handleDragMove) {
|
if (this.strategy.handleDragMove) {
|
||||||
this.strategy.handleDragMove(dragEvent);
|
this.strategy.handleDragMove(dragEvent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle drag auto-scroll
|
|
||||||
this.eventBus.on('drag:auto-scroll', (event: Event) => {
|
this.eventBus.on('drag:auto-scroll', (event: Event) => {
|
||||||
const { draggedElement, snappedY } = (event as CustomEvent).detail;
|
const { draggedElement, snappedY } = (event as CustomEvent).detail;
|
||||||
if (this.strategy.handleDragAutoScroll) {
|
if (this.strategy.handleDragAutoScroll) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue