mirror of
https://github.com/itflow-org/itflow
synced 2026-08-30 11:25:12 +00:00
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
// -------------------------------
|
|
// Drag: Kanban Columns (Statuses)
|
|
// -------------------------------
|
|
new Sortable(document.querySelector('#kanban-board'), {
|
|
animation: 150,
|
|
handle: '.kanban-column-header',
|
|
draggable: '.kanban-column',
|
|
onEnd: function () {
|
|
const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
|
|
status_id: col.dataset.statusId,
|
|
status_kanban: index
|
|
}));
|
|
|
|
if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
|
|
itflowPostForm('ajax.php', {
|
|
update_kanban_status_position: true,
|
|
positions: columnPositions
|
|
}).catch((err) => {
|
|
console.error('Error updating status order:', err);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// -------------------------------
|
|
// Drag: Tasks within Columns
|
|
// -------------------------------
|
|
document.querySelectorAll('.kanban-status').forEach(statusCol => {
|
|
new Sortable(statusCol, {
|
|
group: 'tickets',
|
|
animation: 150,
|
|
// Let the ticket number / subject links work without starting a drag
|
|
filter: 'a',
|
|
preventOnFilter: false,
|
|
handle: isTouchDevice() ? '.drag-handle-class' : undefined,
|
|
onStart: () => hidePlaceholders(),
|
|
onEnd: function (evt) {
|
|
const target = evt.to;
|
|
const movedEl = evt.item;
|
|
|
|
// Disallow reordering in same column if config says so
|
|
if (CONFIG_TICKET_ORDERING === 0 && evt.from === evt.to) {
|
|
evt.from.insertBefore(movedEl, evt.from.children[evt.oldIndex]);
|
|
showPlaceholders();
|
|
return;
|
|
}
|
|
|
|
const columnId = target.dataset.statusId;
|
|
|
|
const positions = Array.from(target.querySelectorAll('.task')).map((card, index) => {
|
|
const ticketId = card.dataset.ticketId;
|
|
const oldStatus = ticketId === movedEl.dataset.ticketId
|
|
? movedEl.dataset.ticketStatusId
|
|
: false;
|
|
|
|
card.dataset.ticketStatusId = columnId; // update DOM
|
|
|
|
return {
|
|
ticket_id: ticketId,
|
|
ticket_order: index,
|
|
ticket_oldStatus: oldStatus,
|
|
ticket_status: columnId
|
|
};
|
|
});
|
|
|
|
itflowPostForm('ajax.php', {
|
|
update_kanban_ticket: true,
|
|
positions: positions
|
|
}).catch((err) => {
|
|
console.error('Error updating ticket positions:', err);
|
|
});
|
|
|
|
// Refresh placeholders after update
|
|
showPlaceholders();
|
|
}
|
|
});
|
|
});
|
|
|
|
// -------------------------------
|
|
// 📱 Touch Support: Show drag handle on mobile
|
|
// -------------------------------
|
|
if (isTouchDevice()) {
|
|
document.querySelectorAll('.drag-handle-class').forEach(function (el) {
|
|
el.style.display = 'inline';
|
|
});
|
|
}
|
|
|
|
// -------------------------------
|
|
// Placeholder Management
|
|
// -------------------------------
|
|
function showPlaceholders() {
|
|
document.querySelectorAll('.kanban-status').forEach(status => {
|
|
const placeholderClass = 'empty-placeholder';
|
|
|
|
// Remove existing placeholder
|
|
const existing = status.querySelector(`.${placeholderClass}`);
|
|
if (existing) existing.remove();
|
|
|
|
// Only show if there are no tasks
|
|
if (status.querySelectorAll('.task').length === 0) {
|
|
const placeholder = document.createElement('div');
|
|
placeholder.className = `${placeholderClass} text-muted text-center p-2`;
|
|
placeholder.innerText = 'Drop ticket here';
|
|
placeholder.style.pointerEvents = 'none';
|
|
status.appendChild(placeholder);
|
|
}
|
|
});
|
|
}
|
|
|
|
function hidePlaceholders() {
|
|
document.querySelectorAll('.empty-placeholder').forEach(el => el.remove());
|
|
}
|
|
|
|
// Run once on load
|
|
showPlaceholders();
|
|
|
|
// -------------------------------
|
|
// Utility: Detect touch device
|
|
// -------------------------------
|
|
function isTouchDevice() {
|
|
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
|
}
|
|
});
|