Revert Fix
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
Reference in New Issue
Block a user