mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-05 10:29:51 +03:00
Fixed drag'n'drop in the Calendar (#5807)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
parent
ca305f21d7
commit
7b466b8410
@ -774,6 +774,9 @@
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
border-bottom: 1px solid var(--global-focus-BorderColor);
|
border-bottom: 1px solid var(--global-focus-BorderColor);
|
||||||
}
|
}
|
||||||
|
&.dragging > * {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ToDo Line */
|
/* ToDo Line */
|
||||||
|
@ -162,6 +162,7 @@
|
|||||||
let scroller: HTMLElement
|
let scroller: HTMLElement
|
||||||
let calendarWidth: number = 0
|
let calendarWidth: number = 0
|
||||||
let calendarRect: DOMRect
|
let calendarRect: DOMRect
|
||||||
|
let containerRect: DOMRect
|
||||||
let colWidth: number = 0
|
let colWidth: number = 0
|
||||||
let nowLineTop: number = -1
|
let nowLineTop: number = -1
|
||||||
let timeNow: string = '--:--'
|
let timeNow: string = '--:--'
|
||||||
@ -539,14 +540,15 @@
|
|||||||
? rem((heightAD + 0.125) * (adMaxRow <= minAD ? adMaxRow : minAD) + 0.25)
|
? rem((heightAD + 0.125) * (adMaxRow <= minAD ? adMaxRow : minAD) + 0.25)
|
||||||
: rem((heightAD + 0.125) * (adMaxRow <= maxAD ? adMaxRow : maxAD) + 0.25)
|
: rem((heightAD + 0.125) * (adMaxRow <= maxAD ? adMaxRow : maxAD) + 0.25)
|
||||||
$: showArrowAD = (!minimizedAD && adMaxRow > maxAD) || (minimizedAD && adMaxRow > minAD)
|
$: showArrowAD = (!minimizedAD && adMaxRow > maxAD) || (minimizedAD && adMaxRow > minAD)
|
||||||
|
$: headerHeight = (showHeader ? rem(heightHeader) : 0) + styleAD
|
||||||
|
|
||||||
const getMinutes = (exactly: number): number => {
|
const getMinutes = (exactly: number): number => {
|
||||||
const roundStep = 60 / stepsPerHour
|
const roundStep = 60 / stepsPerHour
|
||||||
return Math.round(exactly / roundStep) * roundStep
|
return Math.round(exactly / roundStep) * roundStep
|
||||||
}
|
}
|
||||||
|
|
||||||
const getExactly = (e: MouseEvent): number => {
|
const getExactly = (e: MouseEvent, correction: boolean = false): number => {
|
||||||
return Math.round((e.offsetY * 60) / cellHeight)
|
return Math.round((e.offsetY * 60) / cellHeight) - (correction ? 15 : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStickyMinutes = (
|
const getStickyMinutes = (
|
||||||
@ -596,6 +598,7 @@
|
|||||||
let oldTime: number = -1
|
let oldTime: number = -1
|
||||||
let originDate: Timestamp = 0
|
let originDate: Timestamp = 0
|
||||||
let originDueDate: Timestamp = 0
|
let originDueDate: Timestamp = 0
|
||||||
|
let scrollTimer: any = null
|
||||||
|
|
||||||
async function updateHandler (event: Event) {
|
async function updateHandler (event: Event) {
|
||||||
const update: DocumentUpdate<Event> = {}
|
const update: DocumentUpdate<Event> = {}
|
||||||
@ -631,6 +634,7 @@
|
|||||||
directionResize = direction
|
directionResize = direction
|
||||||
originDate = event.date
|
originDate = event.date
|
||||||
originDueDate = event.dueDate
|
originDueDate = event.dueDate
|
||||||
|
containerRect = scroller.getBoundingClientRect()
|
||||||
window.addEventListener('mouseup', mouseUpElement as any)
|
window.addEventListener('mouseup', mouseUpElement as any)
|
||||||
}
|
}
|
||||||
function mouseMoveElement (
|
function mouseMoveElement (
|
||||||
@ -653,11 +657,32 @@
|
|||||||
if (newDate - events[index].date >= 15 * 60000) events[index].dueDate = newDate
|
if (newDate - events[index].date >= 15 * 60000) events[index].dueDate = newDate
|
||||||
}
|
}
|
||||||
events = events
|
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 {
|
function dragStartElement (e: DragEvent & { currentTarget: EventTarget & HTMLDivElement }, event: Event): void {
|
||||||
if (isReadOnly(event) || event.allDay) return
|
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
|
originDate = event.date
|
||||||
originDueDate = event.dueDate
|
originDueDate = event.dueDate
|
||||||
dragOnOld = null
|
dragOnOld = null
|
||||||
@ -674,7 +699,7 @@
|
|||||||
|
|
||||||
function dragDrop (e: DragEvent, day: Date, hourOfDay: number): void {
|
function dragDrop (e: DragEvent, day: Date, hourOfDay: number): void {
|
||||||
const hour = hourOfDay + startHour
|
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 (dragId) {
|
||||||
if (oldTime === -1) oldTime = newTime
|
if (oldTime === -1) oldTime = newTime
|
||||||
const index = events.findIndex((ev) => ev._id === dragId)
|
const index = events.findIndex((ev) => ev._id === dragId)
|
||||||
@ -712,12 +737,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dragOver (e: DragEvent, day: Date, hourOfDay: number): void {
|
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()
|
e.preventDefault()
|
||||||
const dragOn: CalendarCell = {
|
const dragOn: CalendarCell = {
|
||||||
day,
|
day,
|
||||||
hourOfDay,
|
hourOfDay,
|
||||||
minutes: getExactly(e)
|
minutes: getExactly(e, true)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
dragOnOld !== null &&
|
dragOnOld !== null &&
|
||||||
@ -759,6 +787,11 @@
|
|||||||
dispatch('dragEnter', { date: new Date(new Date(newTime).setMinutes(stickyMinutes, 0, 0)) })
|
dispatch('dragEnter', { date: new Date(new Date(newTime).setMinutes(stickyMinutes, 0, 0)) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dragLeave = (e: DragEvent): void => {
|
||||||
|
dispatch('dragOut')
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Scroller
|
<Scroller
|
||||||
@ -768,6 +801,7 @@
|
|||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div
|
<div
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
|
on:dragleave={dragLeave}
|
||||||
on:dragleave
|
on:dragleave
|
||||||
class="calendar-container timeline-grid-bg"
|
class="calendar-container timeline-grid-bg"
|
||||||
class:clearCells={clearCells || resizeId !== null || dragId !== null}
|
class:clearCells={clearCells || resizeId !== null || dragId !== null}
|
||||||
@ -1150,29 +1184,28 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 0.5rem;
|
height: 0.25rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
cursor: row-resize;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: '';
|
content: '';
|
||||||
left: -0.25rem;
|
left: -0.25rem;
|
||||||
right: -0.25rem;
|
right: -0.25rem;
|
||||||
height: 1rem;
|
height: 0.5rem;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: 0.5rem;
|
|
||||||
transition-property: opacity, border-width, transform;
|
transition-property: opacity, border-width, transform;
|
||||||
transition-duration: 0.15s;
|
transition-duration: 0.15s;
|
||||||
transition-timing-function: var(--timing-main);
|
transition-timing-function: var(--timing-main);
|
||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: row-resize;
|
|
||||||
filter: drop-shadow(0 0 2px var(--primary-edit-border-color));
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
&.allowed::after {
|
&.allowed::after {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
z-index: 10;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
&.allowed:hover::after,
|
&.allowed:hover::after,
|
||||||
&.hovered::after {
|
&.hovered::after {
|
||||||
@ -1185,6 +1218,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
&::after {
|
&::after {
|
||||||
top: -0.25rem;
|
top: -0.25rem;
|
||||||
|
border-radius: 0.5rem 0.5rem 0 0;
|
||||||
border-top-color: var(--primary-edit-border-color);
|
border-top-color: var(--primary-edit-border-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1192,6 +1226,7 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
&::after {
|
&::after {
|
||||||
bottom: -0.25rem;
|
bottom: -0.25rem;
|
||||||
|
border-radius: 0 0 0.5rem 0.5rem;
|
||||||
border-bottom-color: var(--primary-edit-border-color);
|
border-bottom-color: var(--primary-edit-border-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
// export let hourHeight: number
|
// export let hourHeight: number
|
||||||
export let size: { width: number, height: number }
|
export let size: { width: number, height: number }
|
||||||
|
|
||||||
$: oneRow = size.height < 42 || event.allDay
|
$: oneRow = size.height < 25 || event.allDay
|
||||||
$: narrow = event.dueDate - event.date < MILLISECONDS_IN_MINUTE * 25
|
$: narrow = event.dueDate - event.date < MILLISECONDS_IN_MINUTE * 25
|
||||||
$: empty = size.width < 44
|
$: empty = size.width < 44
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte'
|
|
||||||
import calendar, { Calendar, Event, generateEventId, getAllEvents } from '@hcengineering/calendar'
|
import calendar, { Calendar, Event, generateEventId, getAllEvents } from '@hcengineering/calendar'
|
||||||
import { DayCalendar, calendarByIdStore, hidePrivateEvents } from '@hcengineering/calendar-resources'
|
import { DayCalendar, calendarByIdStore, hidePrivateEvents } from '@hcengineering/calendar-resources'
|
||||||
import { PersonAccount } from '@hcengineering/contact'
|
import { PersonAccount } from '@hcengineering/contact'
|
||||||
@ -30,7 +29,6 @@
|
|||||||
export let displayedDaysCount = 1
|
export let displayedDaysCount = 1
|
||||||
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
|
||||||
const q = createQuery()
|
const q = createQuery()
|
||||||
|
|
||||||
function getFrom (date: Date): Timestamp {
|
function getFrom (date: Date): Timestamp {
|
||||||
@ -150,6 +148,11 @@
|
|||||||
raw = raw.filter((r) => r._id !== dragItemId)
|
raw = raw.filter((r) => r._id !== dragItemId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function dragOut () {
|
||||||
|
if (dragItemId != null) {
|
||||||
|
raw = raw.filter((r) => r._id !== dragItemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function clear (dragItem: ToDo | null) {
|
function clear (dragItem: ToDo | null) {
|
||||||
if (dragItem === null) {
|
if (dragItem === null) {
|
||||||
@ -219,6 +222,7 @@
|
|||||||
clearCells={dragItem !== null}
|
clearCells={dragItem !== null}
|
||||||
{dragItemId}
|
{dragItemId}
|
||||||
on:dragEnter={dragEnter}
|
on:dragEnter={dragEnter}
|
||||||
|
on:dragOut={dragOut}
|
||||||
on:dragleave={dragLeave}
|
on:dragleave={dragLeave}
|
||||||
on:create={(e) => {
|
on:create={(e) => {
|
||||||
showCreateDialog(e.detail.date, e.detail.withTime)
|
showCreateDialog(e.detail.date, e.detail.withTime)
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
function handleDragStart (event: DragEvent): void {
|
function handleDragStart (event: DragEvent): void {
|
||||||
if (event.dataTransfer) {
|
if (event.dataTransfer) {
|
||||||
event.dataTransfer.effectAllowed = 'all'
|
event.dataTransfer.effectAllowed = 'move'
|
||||||
}
|
}
|
||||||
isDragging = true
|
isDragging = true
|
||||||
dragging.update((state) => ({
|
dragging.update((state) => ({
|
||||||
|
Loading…
Reference in New Issue
Block a user