1
0

fix(task): dragging and dropping on mobile

This change fixes a regression introduced in 1cbb93ea9beea3049c469ba7cc05b07beebf2062.
In that change, the whole task area was made clickable using mouse events directly. Unfortunately, this also prevented the parent component of the task component to recieve them, essentially never getting notified about the mouse movement and thus never dragging the task. I don't know why this is only a problem on Safari, but it might be related to https://github.com/SortableJS/Sortable/issues/1571#issuecomment-535684451

Resolves https://community.vikunja.io/t/task-re-ordering-is-not-working-in-safari/1916
Resolves https://kolaente.dev/vikunja/vikunja/issues/2092
Resolves https://github.com/go-vikunja/vikunja/issues/304

(cherry picked from commit abf92e29facfa91a75fdce4ab04729010cb510f1)
This commit is contained in:
kolaente 2024-09-18 18:00:27 +02:00
parent 9e5d6bad8d
commit 6a68736ca5
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
2 changed files with 18 additions and 19 deletions

1
frontend/.gitignore vendored
View File

@ -13,6 +13,7 @@ node_modules
dist dist
coverage coverage
*.zip *.zip
.vite/
# Test files # Test files
cypress/screenshots cypress/screenshots

View File

@ -1,17 +1,17 @@
<template> <template>
<div> <div>
<div <div
ref="taskContainerRef"
:class="{'is-loading': taskService.loading}" :class="{'is-loading': taskService.loading}"
class="task loader-container single-task" class="task loader-container single-task"
tabindex="-1" tabindex="-1"
@mouseup.stop.self="openTaskDetail" @click="openTaskDetail"
@mousedown.stop.self="focusTaskLink" @keyup.enter="openTaskDetail"
> >
<FancyCheckbox <FancyCheckbox
v-model="task.done" v-model="task.done"
:disabled="(isArchived || disabled) && !canMarkAsDone" :disabled="(isArchived || disabled) && !canMarkAsDone"
@update:modelValue="markAsDone" @update:modelValue="markAsDone"
@click.stop
/> />
<ColorBubble <ColorBubble
@ -23,8 +23,6 @@
<div <div
:class="{ 'done': task.done, 'show-project': showProject && project}" :class="{ 'done': task.done, 'show-project': showProject && project}"
class="tasktext" class="tasktext"
@mouseup.stop.self="openTaskDetail"
@mousedown.stop.self="focusTaskLink"
> >
<span> <span>
<RouterLink <RouterLink
@ -33,6 +31,7 @@
:to="{ name: 'project.index', params: { projectId: task.projectId } }" :to="{ name: 'project.index', params: { projectId: task.projectId } }"
class="task-project mr-1" class="task-project mr-1"
:class="{'mr-2': task.hexColor !== ''}" :class="{'mr-2': task.hexColor !== ''}"
@click.stop
> >
{{ project.title }} {{ project.title }}
</RouterLink> </RouterLink>
@ -42,15 +41,15 @@
:color="getHexColor(task.hexColor)" :color="getHexColor(task.hexColor)"
class="mr-1" class="mr-1"
/> />
<PriorityLabel <PriorityLabel
:priority="task.priority" :priority="task.priority"
:done="task.done" :done="task.done"
class="pr-2" class="pr-2"
/> />
<RouterLink <RouterLink
ref="taskLink" ref="taskLinkRef"
:to="taskDetailRoute" :to="taskDetailRoute"
class="task-link" class="task-link"
tabindex="-1" tabindex="-1"
@ -141,6 +140,7 @@
v-tooltip="$t('task.detail.belongsToProject', {project: project.title})" v-tooltip="$t('task.detail.belongsToProject', {project: project.title})"
:to="{ name: 'project.index', params: { projectId: task.projectId } }" :to="{ name: 'project.index', params: { projectId: task.projectId } }"
class="task-project" class="task-project"
@click.stop
> >
{{ project.title }} {{ project.title }}
</RouterLink> </RouterLink>
@ -148,7 +148,7 @@
<BaseButton <BaseButton
:class="{'is-favorite': task.isFavorite}" :class="{'is-favorite': task.isFavorite}"
class="favorite" class="favorite"
@click="toggleFavorite" @click.stop="toggleFavorite"
> >
<Icon <Icon
v-if="task.isFavorite" v-if="task.isFavorite"
@ -343,24 +343,22 @@ async function toggleFavorite() {
emit('taskUpdated', task.value) emit('taskUpdated', task.value)
} }
const taskLink = ref<HTMLElement | null>(null) const taskLinkRef = ref<HTMLElement | null>(null)
const taskContainerRef = ref<HTMLElement | null>(null)
function hasTextSelected() { function hasTextSelected() {
const isTextSelected = window.getSelection().toString() const isTextSelected = window.getSelection().toString()
return !(typeof isTextSelected === 'undefined' || isTextSelected === '' || isTextSelected === '\n') return !(typeof isTextSelected === 'undefined' || isTextSelected === '' || isTextSelected === '\n')
} }
function openTaskDetail() { function openTaskDetail(event: MouseEvent | KeyboardEvent) {
if (!hasTextSelected()) { if (event.target instanceof HTMLElement) {
taskLink.value.$el.click() const isInteractiveElement = event.target.closest('a, button, input, .favorite, [role="button"]')
if (isInteractiveElement || hasTextSelected()) {
return
}
} }
}
function focusTaskLink() { taskLinkRef.value?.$el.click()
if (!hasTextSelected()) {
taskContainerRef.value.focus()
}
} }
</script> </script>