1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import {
findBoardCardByTaskRef,
getBoardContext,
showBoardError,
updateColumnBadge,
} from "./board-context.js";
import { fetchBoardTasksJson, reorderBoardDomToTaskList } from "./board-cards.js";
import { showCardPopout } from "./board-popout.js";
var draggedCard = null;
var didDrag = false;
function boardRoot() {
return document.querySelector('.board-columns');
}
function clearColumnDropHighlight() {
document.querySelectorAll('.board-column.dropzone.border-primary').forEach(function(el) {
el.classList.remove('border-primary');
});
}
function dragTransferLooksLikeTask(e) {
if (draggedCard) return true;
var types = e.dataTransfer && e.dataTransfer.types;
if (!types || !types.length) return false;
for (var i = 0; i < types.length; i++) {
if (types[i] === 'text/plain' || types[i] === 'Text') return true;
}
return false;
}
function handleDragStart(e) {
var card = e.target.closest && e.target.closest('.board-card');
if (!card) return;
didDrag = true;
draggedCard = card;
e.dataTransfer.effectAllowed = 'move';
try {
e.dataTransfer.setData('text/plain', card.dataset.taskRef || '');
} catch (err) {
/* ignore setData failures in restricted environments */
}
card.classList.add('opacity-50');
}
function handleDragEnd(e) {
var card = (draggedCard && draggedCard.classList.contains('opacity-50') ? draggedCard : null) ||
(e.target.closest && e.target.closest('.board-card'));
if (card) card.classList.remove('opacity-50');
clearColumnDropHighlight();
window.setTimeout(function() {
draggedCard = null;
didDrag = false;
}, 0);
}
function handleCardClick(e) {
if (didDrag) return;
var card = e.target.closest && e.target.closest('.board-card');
if (!card || card.classList.contains('board-card-popout')) return;
e.preventDefault();
showCardPopout(card);
}
function handleBoardDragOver(e) {
var root = boardRoot();
if (!root || !root.contains(e.target)) return;
var col = e.target.closest && e.target.closest('.board-column.dropzone');
if (!col || !dragTransferLooksLikeTask(e)) return;
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
clearColumnDropHighlight();
col.classList.add('border-primary');
}
function pushTaskStatusUpdate(card, newStatus) {
var taskRef = card && card.dataset.taskRef;
if (!taskRef) return Promise.resolve({ ok: false, status: 0 });
var ctx = getBoardContext();
if (!ctx.project) return Promise.resolve({ ok: false, status: 0 });
return fetch('/tasks/update?' + new URLSearchParams({ project: ctx.project, board: ctx.board, task: taskRef }).toString(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: newStatus || 'TODO' })
}).then(function(res) {
return { ok: res.ok, status: res.status };
}).catch(function() {
return { ok: false, status: 0 };
});
}
function handleBoardDrop(e) {
var root = boardRoot();
var col = e.target.closest && e.target.closest('.board-column.dropzone');
if (!col || !root || !root.contains(e.target)) return;
e.preventDefault();
e.stopPropagation();
clearColumnDropHighlight();
var taskRef = '';
try {
taskRef = e.dataTransfer.getData('text/plain') || '';
} catch (err2) {
taskRef = '';
}
var card = draggedCard || findBoardCardByTaskRef(taskRef);
if (!card) return;
var targetColumn = col;
var targetCards = targetColumn.querySelector('.board-column-cards');
if (!targetCards) return;
var sourceColumn = card.closest && card.closest('.board-column');
if (sourceColumn === targetColumn) return;
var newStatus = targetColumn.dataset.status || 'TODO';
var prevStatus = card.dataset.taskStatus || 'TODO';
var sourceCards = sourceColumn && sourceColumn.querySelector('.board-column-cards');
var nextSibling = card.nextSibling;
card.dataset.taskStatus = newStatus;
targetCards.appendChild(card);
updateColumnBadge(sourceColumn);
updateColumnBadge(targetColumn);
pushTaskStatusUpdate(card, newStatus).then(function(result) {
if (result.ok) {
fetchBoardTasksJson().then(function(tasks) {
if (tasks) reorderBoardDomToTaskList(tasks);
});
return;
}
card.dataset.taskStatus = prevStatus;
if (sourceCards) {
if (nextSibling && nextSibling.parentNode === sourceCards) {
sourceCards.insertBefore(card, nextSibling);
} else {
sourceCards.appendChild(card);
}
}
updateColumnBadge(sourceColumn);
updateColumnBadge(targetColumn);
var st = result.status;
var msg = (st === 401 || st === 403)
? 'Not authorized to update tasks (sign in again if needed). The card was moved back.'
: 'Could not save the task move. The card was moved back.';
showBoardError(msg);
});
}
export function bindBoardInteractions() {
var root = boardRoot();
if (!root) return;
root.addEventListener('dragstart', handleDragStart);
root.addEventListener('dragend', handleDragEnd);
root.addEventListener('click', handleCardClick);
root.addEventListener('dragover', handleBoardDragOver, true);
root.addEventListener('drop', handleBoardDrop, true);
}