Adds ColumnDetector manager

Introduces a new manager responsible for detecting the column the mouse is currently over.

This enables event cloning and repositioning within the calendar columns during drag operations, enhancing the user experience.
This commit is contained in:
Janus Knudsen 2025-08-24 21:18:43 +02:00
parent 9c65143df2
commit 906616fe7b
2 changed files with 227 additions and 0 deletions

View file

@ -0,0 +1,225 @@
/**
* ColumnDetector - Bare detect hvilken kolonne musen er over
*/
export class ColumnDetector {
private currentColumn: string | null = null;
private isMouseDown = false;
private lastMousePosition = { x: 0, y: 0 };
private lastLoggedPosition = { x: 0, y: 0 };
private draggedClone: HTMLElement | null = null;
private mouseOffset = { x: 0, y: 0 };
constructor() {
this.init();
}
private init(): void {
// Lyt til mouse move på hele body
document.body.addEventListener('mousemove', this.handleMouseMove.bind(this));
// Lyt til click på hele body
document.body.addEventListener('click', this.handleClick.bind(this));
// Lyt til mouse down og up
document.body.addEventListener('mousedown', this.handleMouseDown.bind(this));
document.body.addEventListener('mouseup', this.handleMouseUp.bind(this));
}
private handleMouseMove(event: MouseEvent): void {
// Hvis musen er holdt nede, tjek for 25px vertikal bevægelse
if (this.isMouseDown) {
const deltaY = Math.abs(event.clientY - this.lastLoggedPosition.y);
if (deltaY >= 25) {
console.log('Mouse dragged 25px vertically:', {
from: this.lastLoggedPosition,
to: { x: event.clientX, y: event.clientY },
verticalDistance: Math.round(deltaY)
});
this.lastLoggedPosition = { x: event.clientX, y: event.clientY };
// Opdater klonens Y-position ved 25px snap (relativt til kolonne)
if (this.draggedClone && this.draggedClone.parentElement) {
const columnRect = this.draggedClone.parentElement.getBoundingClientRect();
const relativeY = event.clientY - columnRect.top - this.mouseOffset.y;
this.draggedClone.style.top = relativeY + 'px';
}
}
}
// Find hvilket element musen er over (altid)
{
const elementUnder = document.elementFromPoint(event.clientX, event.clientY);
if (!elementUnder) {
// Ingen element under musen
if (this.currentColumn !== null) {
console.log('Left all columns');
this.currentColumn = null;
}
return;
}
// Gå op gennem DOM træet for at finde swp-day-column
let element = elementUnder as HTMLElement;
while (element && element.tagName !== 'SWP-DAY-COLUMN') {
element = element.parentElement as HTMLElement;
if (!element) {
// Ikke i en kolonne
if (this.currentColumn !== null) {
console.log('Left all columns');
this.currentColumn = null;
}
return;
}
}
// Vi fandt en kolonne
const date = element.dataset.date;
if (date && date !== this.currentColumn) {
console.log('Entered column:', date);
this.currentColumn = date;
// Flyt klonen til ny kolonne ved kolonneskift
if (this.draggedClone && this.isMouseDown) {
// Flyt klonen til den nye kolonne
const newColumnElement = document.querySelector(`swp-day-column[data-date="${date}"]`);
if (newColumnElement) {
newColumnElement.appendChild(this.draggedClone);
// Opdater Y-position relativt til den nye kolonne
const columnRect = newColumnElement.getBoundingClientRect();
const relativeY = event.clientY - columnRect.top - this.mouseOffset.y;
this.draggedClone.style.top = relativeY + 'px';
}
}
}
}
}
private handleClick(event: MouseEvent): void {
const target = event.target as HTMLElement;
// Find event element
let eventElement = target;
while (eventElement && eventElement.tagName !== 'SWP-EVENTS-LAYER') {
if (eventElement.tagName === 'SWP-EVENT' || eventElement.tagName === 'SWP-ALLDAY-EVENT') {
break;
}
eventElement = eventElement.parentElement as HTMLElement;
if (!eventElement) return;
}
// Hvis vi nåede til SWP-EVENTS-LAYER uden at finde et event, så return
if (!eventElement || eventElement.tagName === 'SWP-EVENTS-LAYER') {
return;
}
// Log event info
const eventId = eventElement.dataset.eventId;
const eventType = eventElement.dataset.type;
console.log('Clicked event:', {
id: eventId,
type: eventType,
element: eventElement,
title: eventElement.textContent
});
}
private handleMouseDown(event: MouseEvent): void {
this.isMouseDown = true;
this.lastMousePosition = { x: event.clientX, y: event.clientY };
this.lastLoggedPosition = { x: event.clientX, y: event.clientY };
console.log('Mouse down at:', this.lastMousePosition);
// Tjek om mousedown er på et event
const target = event.target as HTMLElement;
let eventElement = target;
while (eventElement && eventElement.tagName !== 'SWP-EVENTS-LAYER') {
if (eventElement.tagName === 'SWP-EVENT' || eventElement.tagName === 'SWP-ALLDAY-EVENT') {
break;
}
eventElement = eventElement.parentElement as HTMLElement;
if (!eventElement) return;
}
// Hvis vi nåede til SWP-EVENTS-LAYER uden at finde et event, så return
if (!eventElement || eventElement.tagName === 'SWP-EVENTS-LAYER') {
return;
}
// Hvis vi fandt et event, lav en clone
if (eventElement) {
this.cloneEvent(eventElement, event);
}
}
private cloneEvent(originalEvent: HTMLElement, mouseEvent: MouseEvent): void {
// Lav en clone
const clone = originalEvent.cloneNode(true) as HTMLElement;
// Præfiks ID med "clone-"
const originalId = originalEvent.dataset.eventId;
if (originalId) {
clone.dataset.eventId = `clone-${originalId}`;
}
// Beregn hvor på event'et musen klikkede
const eventRect = originalEvent.getBoundingClientRect();
this.mouseOffset = {
x: mouseEvent.clientX - eventRect.left, // Stadig nødvendig for cursor placering
y: mouseEvent.clientY - eventRect.top
};
// Gør klonen ready til at blive trukket
clone.style.position = 'absolute';
clone.style.zIndex = '999999';
clone.style.pointerEvents = 'none';
// Sæt størrelse fra det originale event
clone.style.width = eventRect.width + 'px';
clone.style.height = eventRect.height + 'px';
// Find den aktuelle kolonne og placer klonen der
const currentColumnElement = document.querySelector(`swp-day-column[data-date="${this.currentColumn}"]`);
if (currentColumnElement) {
// Sæt initial position relativt til kolonnen
const columnRect = currentColumnElement.getBoundingClientRect();
const relativeY = mouseEvent.clientY - columnRect.top - this.mouseOffset.y;
clone.style.top = relativeY + 'px';
currentColumnElement.appendChild(clone);
} else {
console.error('Could not find current column element:', this.currentColumn);
// Fallback til original placering
originalEvent.parentNode?.insertBefore(clone, originalEvent.nextSibling);
}
// Gem reference til klonen
this.draggedClone = clone;
console.log('Cloned event:', {
original: originalId,
clone: clone.dataset.eventId,
offset: this.mouseOffset
});
}
private handleMouseUp(event: MouseEvent): void {
this.isMouseDown = false;
console.log('Mouse up at:', { x: event.clientX, y: event.clientY });
// Ryd op - fjern klonen (DISABLED FOR DEBUGGING)
// if (this.draggedClone) {
// this.draggedClone.remove();
// this.draggedClone = null;
// console.log('Removed clone');
// }
}
public destroy(): void {
document.body.removeEventListener('mousemove', this.handleMouseMove.bind(this));
document.body.removeEventListener('click', this.handleClick.bind(this));
document.body.removeEventListener('mousedown', this.handleMouseDown.bind(this));
document.body.removeEventListener('mouseup', this.handleMouseUp.bind(this));
}
}