Improves scroll and interaction behavior in schedule view
Enhances dragging and clicking interactions for schedule containers - Adds drag threshold to prevent unintended scrolling - Prevents click events during dragging - Updates time badge selectors for consistent element handling Fixes potential usability issues with schedule cell interactions
This commit is contained in:
parent
531c681b7d
commit
408e590922
1 changed files with 34 additions and 10 deletions
|
|
@ -448,6 +448,7 @@ class ScheduleController {
|
||||||
scrollContainers.forEach(container => {
|
scrollContainers.forEach(container => {
|
||||||
const el = container as HTMLElement;
|
const el = container as HTMLElement;
|
||||||
let isDown = false;
|
let isDown = false;
|
||||||
|
let hasDragged = false;
|
||||||
let startX = 0;
|
let startX = 0;
|
||||||
let scrollLeft = 0;
|
let scrollLeft = 0;
|
||||||
|
|
||||||
|
|
@ -456,7 +457,7 @@ class ScheduleController {
|
||||||
if ((e.target as HTMLElement).closest('swp-btn, input, select')) return;
|
if ((e.target as HTMLElement).closest('swp-btn, input, select')) return;
|
||||||
|
|
||||||
isDown = true;
|
isDown = true;
|
||||||
el.classList.add('dragging');
|
hasDragged = false;
|
||||||
startX = e.clientX;
|
startX = e.clientX;
|
||||||
scrollLeft = el.scrollLeft;
|
scrollLeft = el.scrollLeft;
|
||||||
};
|
};
|
||||||
|
|
@ -464,20 +465,43 @@ class ScheduleController {
|
||||||
const onMouseUp = () => {
|
const onMouseUp = () => {
|
||||||
isDown = false;
|
isDown = false;
|
||||||
el.classList.remove('dragging');
|
el.classList.remove('dragging');
|
||||||
|
|
||||||
|
// Reset hasDragged after a short delay to allow click events to check it
|
||||||
|
setTimeout(() => { hasDragged = false; }, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
const onMouseMove = (e: MouseEvent) => {
|
||||||
if (!isDown) return;
|
if (!isDown) return;
|
||||||
e.preventDefault();
|
|
||||||
const x = e.clientX;
|
const x = e.clientX;
|
||||||
|
const diff = Math.abs(startX - x);
|
||||||
|
|
||||||
|
// Only start dragging after moving 5px (allows clicks/double-clicks)
|
||||||
|
if (!hasDragged && diff > 5) {
|
||||||
|
hasDragged = true;
|
||||||
|
el.classList.add('dragging');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDragged) return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
const walk = (startX - x) * 1.5;
|
const walk = (startX - x) * 1.5;
|
||||||
el.scrollLeft = scrollLeft + walk;
|
el.scrollLeft = scrollLeft + walk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Prevent click events if we just dragged
|
||||||
|
const onClick = (e: MouseEvent) => {
|
||||||
|
if (hasDragged) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
el.addEventListener('mousedown', onMouseDown);
|
el.addEventListener('mousedown', onMouseDown);
|
||||||
el.addEventListener('mouseup', onMouseUp);
|
el.addEventListener('mouseup', onMouseUp);
|
||||||
el.addEventListener('mouseleave', onMouseUp);
|
el.addEventListener('mouseleave', onMouseUp);
|
||||||
el.addEventListener('mousemove', onMouseMove);
|
el.addEventListener('mousemove', onMouseMove);
|
||||||
|
el.addEventListener('click', onClick, true); // capture phase
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -741,13 +765,13 @@ class ScheduleController {
|
||||||
* Prefill form from cell data
|
* Prefill form from cell data
|
||||||
*/
|
*/
|
||||||
private prefillFormFromCell(cell: HTMLElement): void {
|
private prefillFormFromCell(cell: HTMLElement): void {
|
||||||
const timeDisplay = cell.querySelector('swp-time-display');
|
const timeBadge = cell.querySelector('swp-time-badge');
|
||||||
if (!timeDisplay) return;
|
if (!timeBadge) return;
|
||||||
|
|
||||||
let status = 'work';
|
let status = 'work';
|
||||||
if (timeDisplay.classList.contains('off')) status = 'off';
|
if (timeBadge.classList.contains('off')) status = 'off';
|
||||||
else if (timeDisplay.classList.contains('vacation')) status = 'vacation';
|
else if (timeBadge.classList.contains('vacation')) status = 'vacation';
|
||||||
else if (timeDisplay.classList.contains('sick')) status = 'sick';
|
else if (timeBadge.classList.contains('sick')) status = 'sick';
|
||||||
|
|
||||||
// Update status options
|
// Update status options
|
||||||
document.querySelectorAll('#scheduleStatusOptions swp-status-option').forEach(opt => {
|
document.querySelectorAll('#scheduleStatusOptions swp-status-option').forEach(opt => {
|
||||||
|
|
@ -760,7 +784,7 @@ class ScheduleController {
|
||||||
|
|
||||||
// Parse time if work status
|
// Parse time if work status
|
||||||
if (status === 'work') {
|
if (status === 'work') {
|
||||||
const timeText = timeDisplay.textContent?.trim() || '';
|
const timeText = timeBadge.textContent?.trim() || '';
|
||||||
const timeMatch = timeText.match(/(\d{2}:\d{2})\s*-\s*(\d{2}:\d{2})/);
|
const timeMatch = timeText.match(/(\d{2}:\d{2})\s*-\s*(\d{2}:\d{2})/);
|
||||||
if (timeMatch) {
|
if (timeMatch) {
|
||||||
this.setTimeRange(timeMatch[1], timeMatch[2]);
|
this.setTimeRange(timeMatch[1], timeMatch[2]);
|
||||||
|
|
@ -1008,7 +1032,7 @@ class ScheduleController {
|
||||||
const formattedTime = `${startTime} - ${endTime}`;
|
const formattedTime = `${startTime} - ${endTime}`;
|
||||||
|
|
||||||
this.selectedCells.forEach(cell => {
|
this.selectedCells.forEach(cell => {
|
||||||
const timeDisplay = cell.querySelector('swp-time-display');
|
const timeDisplay = cell.querySelector('swp-time-badge');
|
||||||
if (timeDisplay && !timeDisplay.classList.contains('off') &&
|
if (timeDisplay && !timeDisplay.classList.contains('off') &&
|
||||||
!timeDisplay.classList.contains('vacation') &&
|
!timeDisplay.classList.contains('vacation') &&
|
||||||
!timeDisplay.classList.contains('sick')) {
|
!timeDisplay.classList.contains('sick')) {
|
||||||
|
|
@ -1032,7 +1056,7 @@ class ScheduleController {
|
||||||
const endTime = endInput ? this.valueToTime(parseInt(endInput.value)) : '17:00';
|
const endTime = endInput ? this.valueToTime(parseInt(endInput.value)) : '17:00';
|
||||||
|
|
||||||
this.selectedCells.forEach(cell => {
|
this.selectedCells.forEach(cell => {
|
||||||
const timeDisplay = cell.querySelector('swp-time-display');
|
const timeDisplay = cell.querySelector('swp-time-badge');
|
||||||
if (!timeDisplay) return;
|
if (!timeDisplay) return;
|
||||||
|
|
||||||
timeDisplay.classList.remove('off', 'off-override', 'vacation', 'sick');
|
timeDisplay.classList.remove('off', 'off-override', 'vacation', 'sick');
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue