From 7b466b841098ee9ea50ad8e2b21a2f04d67b4742 Mon Sep 17 00:00:00 2001 From: Alexander Platov Date: Thu, 13 Jun 2024 18:18:18 +0300 Subject: [PATCH] Fixed drag'n'drop in the Calendar (#5807) Signed-off-by: Alexander Platov --- packages/theme/styles/components.scss | 3 + .../src/components/DayCalendar.svelte | 59 +++++++++++++++---- .../src/components/EventElement.svelte | 2 +- .../src/components/PlanningCalendar.svelte | 8 ++- .../src/components/ToDoDraggable.svelte | 2 +- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/packages/theme/styles/components.scss b/packages/theme/styles/components.scss index 9a7e0fae41..e90fc9be7b 100644 --- a/packages/theme/styles/components.scss +++ b/packages/theme/styles/components.scss @@ -774,6 +774,9 @@ inset: 0; border-bottom: 1px solid var(--global-focus-BorderColor); } + &.dragging > * { + opacity: .5; + } } /* ToDo Line */ diff --git a/plugins/calendar-resources/src/components/DayCalendar.svelte b/plugins/calendar-resources/src/components/DayCalendar.svelte index f7a7e56dc7..54d9343e2a 100644 --- a/plugins/calendar-resources/src/components/DayCalendar.svelte +++ b/plugins/calendar-resources/src/components/DayCalendar.svelte @@ -162,6 +162,7 @@ let scroller: HTMLElement let calendarWidth: number = 0 let calendarRect: DOMRect + let containerRect: DOMRect let colWidth: number = 0 let nowLineTop: number = -1 let timeNow: string = '--:--' @@ -539,14 +540,15 @@ ? rem((heightAD + 0.125) * (adMaxRow <= minAD ? adMaxRow : minAD) + 0.25) : rem((heightAD + 0.125) * (adMaxRow <= maxAD ? adMaxRow : maxAD) + 0.25) $: showArrowAD = (!minimizedAD && adMaxRow > maxAD) || (minimizedAD && adMaxRow > minAD) + $: headerHeight = (showHeader ? rem(heightHeader) : 0) + styleAD const getMinutes = (exactly: number): number => { const roundStep = 60 / stepsPerHour return Math.round(exactly / roundStep) * roundStep } - const getExactly = (e: MouseEvent): number => { - return Math.round((e.offsetY * 60) / cellHeight) + const getExactly = (e: MouseEvent, correction: boolean = false): number => { + return Math.round((e.offsetY * 60) / cellHeight) - (correction ? 15 : 0) } const getStickyMinutes = ( @@ -596,6 +598,7 @@ let oldTime: number = -1 let originDate: Timestamp = 0 let originDueDate: Timestamp = 0 + let scrollTimer: any = null async function updateHandler (event: Event) { const update: DocumentUpdate = {} @@ -631,6 +634,7 @@ directionResize = direction originDate = event.date originDueDate = event.dueDate + containerRect = scroller.getBoundingClientRect() window.addEventListener('mouseup', mouseUpElement as any) } function mouseMoveElement ( @@ -653,11 +657,32 @@ if (newDate - events[index].date >= 15 * 60000) events[index].dueDate = newDate } events = events + + if (!scrollTimer) { + directionScroll( + e.clientY < containerRect.y + headerHeight + 16 && scroller.scrollTop > 0 + ? 'top' + : e.clientY > containerRect.bottom - 16 && scroller.scrollHeight - scroller.scrollTop > scroller.clientHeight + ? 'bottom' + : 'none' + ) + } } + const directionScroll = (direction: 'top' | 'bottom' | 'none'): void => { + if (direction === 'none') return + scrollTimer = setTimeout(() => (scrollTimer = null), 150) + scroller.scrollBy({ top: direction === 'top' ? -cellHeight * 2 : cellHeight * 2, left: 0, behavior: 'smooth' }) + } + + const transparentImage = new Image(1, 1) + transparentImage.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' function dragStartElement (e: DragEvent & { currentTarget: EventTarget & HTMLDivElement }, event: Event): void { if (isReadOnly(event) || event.allDay) return - if (e.dataTransfer) e.dataTransfer.effectAllowed = 'all' + if (e.dataTransfer) { + e.dataTransfer.setDragImage(transparentImage, 0, 0) + e.dataTransfer.effectAllowed = 'move' + } originDate = event.date originDueDate = event.dueDate dragOnOld = null @@ -674,7 +699,7 @@ function dragDrop (e: DragEvent, day: Date, hourOfDay: number): void { const hour = hourOfDay + startHour - const newTime = new Date(day).setHours(hour, getExactly(e), 0, 0) + const newTime = new Date(day).setHours(hour, getExactly(e, true), 0, 0) if (dragId) { if (oldTime === -1) oldTime = newTime const index = events.findIndex((ev) => ev._id === dragId) @@ -712,12 +737,15 @@ } function dragOver (e: DragEvent, day: Date, hourOfDay: number): void { - if (e.dataTransfer) e.dataTransfer.dropEffect = 'move' + if (e.dataTransfer) { + e.dataTransfer.setDragImage(transparentImage, 0, 0) + e.dataTransfer.dropEffect = 'move' + } e.preventDefault() const dragOn: CalendarCell = { day, hourOfDay, - minutes: getExactly(e) + minutes: getExactly(e, true) } if ( dragOnOld !== null && @@ -759,6 +787,11 @@ dispatch('dragEnter', { date: new Date(new Date(newTime).setMinutes(stickyMinutes, 0, 0)) }) } } + + const dragLeave = (e: DragEvent): void => { + dispatch('dragOut') + e.preventDefault() + }
- import { createEventDispatcher } from 'svelte' import calendar, { Calendar, Event, generateEventId, getAllEvents } from '@hcengineering/calendar' import { DayCalendar, calendarByIdStore, hidePrivateEvents } from '@hcengineering/calendar-resources' import { PersonAccount } from '@hcengineering/contact' @@ -30,7 +29,6 @@ export let displayedDaysCount = 1 export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent - const dispatch = createEventDispatcher() const q = createQuery() function getFrom (date: Date): Timestamp { @@ -150,6 +148,11 @@ raw = raw.filter((r) => r._id !== dragItemId) } } + function dragOut () { + if (dragItemId != null) { + raw = raw.filter((r) => r._id !== dragItemId) + } + } function clear (dragItem: ToDo | null) { if (dragItem === null) { @@ -219,6 +222,7 @@ clearCells={dragItem !== null} {dragItemId} on:dragEnter={dragEnter} + on:dragOut={dragOut} on:dragleave={dragLeave} on:create={(e) => { showCreateDialog(e.detail.date, e.detail.withTime) diff --git a/plugins/time-resources/src/components/ToDoDraggable.svelte b/plugins/time-resources/src/components/ToDoDraggable.svelte index 5c7374d67b..2305f7e23c 100644 --- a/plugins/time-resources/src/components/ToDoDraggable.svelte +++ b/plugins/time-resources/src/components/ToDoDraggable.svelte @@ -58,7 +58,7 @@ function handleDragStart (event: DragEvent): void { if (event.dataTransfer) { - event.dataTransfer.effectAllowed = 'all' + event.dataTransfer.effectAllowed = 'move' } isDragging = true dragging.update((state) => ({