Revert Fix

This commit is contained in:
johnnyq
2025-04-13 15:15:18 -04:00
parent 846947ff49
commit 691aebce91
2 changed files with 166 additions and 144 deletions

View File

@@ -1,41 +1,83 @@
/* General Popover Styling */
.popover { .popover {
max-width: 600px; max-width: 600px;
} }
/* Kanban Board Container */
#kanban-board { #kanban-board {
display: flex; display: flex;
box-sizing: border-box;
overflow-x: auto; overflow-x: auto;
box-sizing: border-box;
min-width: 400px; min-width: 400px;
height: calc(100vh - 210px); height: calc(100vh - 210px);
} }
/* Kanban Column */
.kanban-column { .kanban-column {
flex: 1; /* Allows columns to grow equally */ flex: 1;
margin: 0 10px; /* Space between columns */
min-width: 300px; min-width: 300px;
max-width: 300px; max-width: 300px;
margin: 0 10px;
background: #f4f4f4; background: #f4f4f4;
padding: 10px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
min-height: calc(100vh - 230px); min-height: calc(100vh - 230px);
max-height: calc(100vh - 230px); max-height: calc(100vh - 230px);
box-sizing: border-box; box-sizing: border-box;
display: flex;
flex-direction: column;
} }
.kanban-column div { /* Column Inner Scrollable Task Area */
max-height: calc(100vh - 280px); /* Set your desired max height */ .kanban-status {
overflow-y: auto; /* Adds a scrollbar when content exceeds max height */ flex: 1;
overflow-y: auto;
min-height: 60px;
position: relative;
padding: 5px;
background-color: #f9f9f9;
border-radius: 4px;
} }
/* Individual Task Cards */
.task { .task {
background: #fff; background: #fff;
margin: 5px 0; margin: 5px 0;
padding: 10px; padding: 10px;
border: 1px solid #ddd; border: 1px solid #ddd;
user-select: none; /* Prevent text selection */ border-radius: 4px;
cursor: grab;
user-select: none;
} }
.drag-handle-class { /* Grabbing Cursor State */
touch-action: none; .task:active {
float: right; cursor: grabbing;
}
/* Drag Handle (shown on mobile or with class targeting) */
.drag-handle-class {
float: right;
touch-action: none;
cursor: grab;
}
/* Placeholder shown in empty columns */
.empty-placeholder {
border: 2px dashed #ccc;
background-color: #fcfcfc;
color: #999;
font-style: italic;
padding: 12px;
margin: 10px 0;
text-align: center;
border-radius: 4px;
pointer-events: none;
}
/* Sortable drop zone feedback (optional visual cue) */
.kanban-status.sortable-over {
background-color: #eaf6ff;
transition: background-color 0.2s ease;
} }

View File

@@ -1,146 +1,126 @@
$(document).ready(function() { $(document).ready(function () {
console.log('CONFIG_TICKET_MOVING_COLUMNS: ' + CONFIG_TICKET_MOVING_COLUMNS); console.log('CONFIG_TICKET_MOVING_COLUMNS:', CONFIG_TICKET_MOVING_COLUMNS);
console.log('CONFIG_TICKET_ORDERING: ' + CONFIG_TICKET_ORDERING); console.log('CONFIG_TICKET_ORDERING:', CONFIG_TICKET_ORDERING);
// Function to detect touch devices // -------------------------------
function isTouchDevice() { // Drag: Kanban Columns (Statuses)
return 'ontouchstart' in window || navigator.maxTouchPoints; // -------------------------------
} new Sortable(document.querySelector('#kanban-board'), {
animation: 150,
// Initialize Dragula for the Kanban board handle: '.panel-title',
let boardDrake = dragula([ draggable: '.kanban-column',
document.querySelector('#kanban-board') onEnd: function () {
], { const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
moves: function(el, container, handle) { status_id: $(col).data('status-id'),
return handle.classList.contains('panel-title');
},
accepts: function(el, target, source, sibling) {
return CONFIG_TICKET_MOVING_COLUMNS === 1;
}
});
// Log the event of moving the column panel-title
boardDrake.on('drag', function(el) {
//console.log('Dragging column:', el.querySelector('.panel-title').innerText);
});
boardDrake.on('drop', function(el, target, source, sibling) {
//console.log('Dropped column:', el.querySelector('.panel-title').innerText);
// Get all columns and their positions
let columns = document.querySelectorAll('#kanban-board .kanban-column');
let columnPositions = [];
columns.forEach(function(column, index) {
let statusId = $(column).data('status-id'); // Assuming you have a data attribute for status ID
columnPositions.push({
status_id: statusId,
status_kanban: index status_kanban: index
}); }));
});
// Send AJAX request to update all column positions if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
$.ajax({ $.post('ajax.php', {
url: 'ajax.php', update_kanban_status_position: true,
type: 'POST', positions: columnPositions
data: { }).done(() => {
update_kanban_status_position: true, console.log('Ticket status kanban orders updated.');
positions: columnPositions }).fail((xhr) => {
}, console.error('Error updating status order:', xhr.responseText);
success: function(response) { });
console.log('Ticket status kanban orders updated successfully.');
// Optionally, you can refresh the page or update the UI here
},
error: function(xhr, status, error) {
console.error('Error updating ticket status kanban orders:', error);
}
});
});
// Initialize Dragula for the Kanban Cards
let drake = dragula([
...document.querySelectorAll('#status')
], {
moves: function(el, container, handle) {
if (isTouchDevice()) {
return handle.classList.contains('drag-handle-class');
} else {
return true; // Allow dragging on the entire task element for desktop
} }
} }
}); });
// -------------------------------
// Drag: Tasks within Columns
// -------------------------------
document.querySelectorAll('.kanban-status').forEach(statusCol => {
new Sortable(statusCol, {
group: 'tickets',
animation: 150,
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).data('status-id');
const positions = Array.from(target.querySelectorAll('.task')).map((card, index) => {
const ticketId = $(card).data('ticket-id');
const oldStatus = ticketId === $(movedEl).data('ticket-id')
? $(movedEl).data('ticket-status-id')
: false;
$(card).data('ticket-status-id', columnId); // update DOM
return {
ticket_id: ticketId,
ticket_order: index,
ticket_oldStatus: oldStatus,
ticket_status: columnId
};
});
$.post('ajax.php', {
update_kanban_ticket: true,
positions: positions
}).done(() => {
console.log('Updated kanban ticket positions.');
}).fail((xhr) => {
console.error('Error updating ticket positions:', xhr.responseText);
});
// Refresh placeholders after update
showPlaceholders();
}
});
});
// -------------------------------
// 📱 Touch Support: Show drag handle on mobile
// -------------------------------
if (isTouchDevice()) { if (isTouchDevice()) {
const moveList = document.querySelectorAll('.task'); $('.drag-handle-class').css('display', 'inline');
moveList.forEach(task => { }
task.querySelector('.drag-handle-class').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);
}
}); });
} }
drake.on('drag', function(el) { function hidePlaceholders() {
el.style.cursor = 'grabbing'; document.querySelectorAll('.empty-placeholder').forEach(el => el.remove());
}); }
drake.on('dragend', function(el) {
el.style.cursor = 'grab';
});
// Add event listener for the drop event
drake.on('drop', function (el, target, source, sibling) {
// Log the target ID to the console
//console.log('Dropped into:', target.getAttribute('data-column-name'));
if (CONFIG_TICKET_ORDERING === 0 && source == target) { // Run once on load
drake.cancel(true); // Move the card back to its original position showPlaceholders();
return;
}
// Get all cards in the target column and their positions
let cards = $(target).children('.task');
let positions = [];
//id of current status / column // -------------------------------
let columnId = $(target).data('status-id'); // Utility: Detect touch device
// -------------------------------
let movedTicketId = $(el).data('ticket-id'); function isTouchDevice() {
let movedTicketStatusId = $(el).data('ticket-status-id'); return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
}
cards.each(function(index, card) { });
let ticketId = $(card).data('ticket-id');
let statusId = $(card).data('ticket-status-id');
let oldStatus = false;
if (ticketId == movedTicketId) {
oldStatus = movedTicketStatusId;
}
//update the status id of the card if needed
if (statusId != columnId) {
$(card).data('ticket-status-id', columnId);
statusId = columnId;
}
positions.push({
ticket_id: ticketId,
ticket_order: index,
ticket_oldStatus: oldStatus,
ticket_status: statusId ?? null// Get the new status ID from the target column
});
});
//console.log(positions);
// Send AJAX request to update all ticket kanban orders and statuses
$.ajax({
url: 'ajax.php',
type: 'POST',
data: {
update_kanban_ticket: true,
positions: positions
},
success: function(response) {
//console.log('Ticket kanban orders and statuses updated successfully.');
},
error: function(xhr, status, error) {
console.error('Error updating ticket kanban orders and statuses:', error);
}
});
});
});