mirror of
https://github.com/itflow-org/itflow
synced 2026-02-28 02:44:53 +00:00
Update more broken links from file diretory consolidation and started migrating some js and ajax and css from root to /user /admin etc that pertain to the section
This commit is contained in:
@@ -1,37 +0,0 @@
|
||||
function fetchSSL(type)
|
||||
{
|
||||
// Get the domain name input & issued/expire/key fields, based on whether this is a new cert or updating an existing
|
||||
if (type == 'new') {
|
||||
var domain = document.getElementById("domain").value;
|
||||
var issuedBy = document.getElementById("issuedBy");
|
||||
var expire = document.getElementById("expire");
|
||||
var publicKey = document.getElementById("publicKey");
|
||||
|
||||
}
|
||||
if (type == 'edit') {
|
||||
var domain = document.getElementById("editCertificateDomain").value;
|
||||
var issuedBy = document.getElementById("editCertificateIssuedBy");
|
||||
var expire = document.getElementById("editCertificateExpire");
|
||||
var publicKey = document.getElementById("editCertificatePublicKey");
|
||||
}
|
||||
|
||||
//Send a GET request to post.php as post.php?certificate_fetch_parse_json_details=TRUE&domain=DOMAIN
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{certificate_fetch_parse_json_details: 'TRUE', domain: domain},
|
||||
function(data) {
|
||||
//If we get a response from post.php, parse it as JSON
|
||||
const ssl_data = JSON.parse(data);
|
||||
|
||||
if (ssl_data.success == "TRUE") {
|
||||
// Fill the form fields with the cert data
|
||||
issuedBy.value = ssl_data.issued_by;
|
||||
expire.value = ssl_data.expire;
|
||||
publicKey.value = ssl_data.public_key;
|
||||
}
|
||||
else{
|
||||
alert("Error whilst parsing/retrieving details for domain")
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Force the user to correctly type the client name to be deleted before activating the button to delete a client
|
||||
function validateClientNameDelete(client_id) {
|
||||
if (document.getElementById("clientNameProvided" + client_id).value === document.getElementById("clientName" + client_id).value) {
|
||||
document.getElementById("clientDeleteButton" + client_id).className = "btn btn-danger btn-lg px-5";
|
||||
}
|
||||
else{
|
||||
document.getElementById("clientDeleteButton" + client_id).className = "btn btn-danger btn-lg px-5 disabled";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
function showOTPViaCredentialID(credential_id) {
|
||||
// Send a GET request to ajax.php as ajax.php?get_totp_token_via_id=true&credential_id=ID
|
||||
jQuery.get(
|
||||
"ajax.php", {
|
||||
"../ajax.php", {
|
||||
get_totp_token_via_id: 'true',
|
||||
credential_id: credential_id
|
||||
},
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
function populateFileDeleteModal(file_id, file_name) {
|
||||
// Dynamically populate the file delete modal with the file id (hidden) and name
|
||||
document.getElementById("file_delete_id").value = file_id;
|
||||
document.getElementById("file_delete_name").innerText = file_name;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ function generateShareLink() {
|
||||
if (item_expires) {
|
||||
// Send a GET request to ajax.php as ajax.php?share_generate_link=true....
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
"../ajax.php",
|
||||
{share_generate_link: 'true', client_id: client_id, type: item_type, id: item_ref_id, note: item_note ,views: item_views, expires: item_expires, contact_email},
|
||||
function(data) {
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* LISTENERS
|
||||
*/
|
||||
|
||||
// Modal loaded listener - populate client select
|
||||
const changeClientModalLoad = document.getElementById('clientChangeTicketModalLoad');
|
||||
changeClientModalLoad.addEventListener('click', function() {
|
||||
populateChangeClientModal_Clients();
|
||||
})
|
||||
|
||||
// Client selected listener - populate contact select
|
||||
// We seem to have to use jQuery to listen for events, as the client input is a select2 component?
|
||||
const clientSelectDropdown = document.getElementById("changeClientSelect");
|
||||
$(clientSelectDropdown).on('select2:select', function (e) {
|
||||
let client_id = $(this).find(':selected').val();
|
||||
populateChangeClientModal_Contacts(client_id);
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTIONS
|
||||
*/
|
||||
|
||||
// Populate client list function
|
||||
function populateChangeClientModal_Clients() {
|
||||
|
||||
// Get current client ID
|
||||
let current_client_id = document.getElementById("client_id").value;
|
||||
|
||||
// Send a GET request to ajax.php as ajax.php?get_active_clients=true
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_active_clients: 'true'},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for clients (multiple)
|
||||
const clients = response.clients;
|
||||
|
||||
// Client dropdown already defined in listeners as clientSelectDropdown
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = clientSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
clientSelectDropdown.remove(i);
|
||||
}
|
||||
clientSelectDropdown[clientSelectDropdown.length] = new Option('- Client -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
clients.forEach(client => {
|
||||
if (parseInt(current_client_id) !== parseInt(client.client_id)) {
|
||||
// Show clients returned (excluding the current client ID - we can't change a ticket client to itself)
|
||||
clientSelectDropdown[clientSelectDropdown.length] = new Option(client.client_name, client.client_id);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client contact function (after a client is selected)
|
||||
function populateChangeClientModal_Contacts(client_id) {
|
||||
// Send a GET request to ajax.php as ajax.php?get_client_contacts=true&client_id=NUM
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_contacts: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for contacts (multiple)
|
||||
const contacts = response.contacts;
|
||||
|
||||
// Contacts dropdown
|
||||
const contactSelectDropdown = document.getElementById("changeContactSelect");
|
||||
|
||||
// Clear Category dropdown
|
||||
let i, L = contactSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
contactSelectDropdown.remove(i);
|
||||
}
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option('- Contact -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
contacts.forEach(contact => {
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option(contact.contact_name, contact.contact_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Collision detection
|
||||
// Adds a "view" entry of the current ticket every 2 mins into the database
|
||||
// Updates the currently viewing (ticket_collision_viewing) element with anyone that's looked at this ticket in the last two mins
|
||||
function ticket_collision_detection() {
|
||||
|
||||
// Get the page ticket id
|
||||
var ticket_id = document.getElementById("ticket_id").value;
|
||||
|
||||
//Send a GET request to ajax.php as ajax.php?ticket_add_view=true&ticket_id=NUMBER
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{ticket_add_view: 'true', ticket_id: ticket_id},
|
||||
function(data) {
|
||||
// We don't care about a response
|
||||
}
|
||||
);
|
||||
|
||||
//Send a GET request to ajax.php as ajax.php?ticket_query_views=true&ticket_id=NUMBER
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{ticket_query_views: 'true', ticket_id: ticket_id},
|
||||
function(data) {
|
||||
//If we get a response from ajax.php, parse it as JSON
|
||||
const ticket_view_data = JSON.parse(data);
|
||||
document.getElementById("ticket_collision_viewing").innerHTML = ticket_view_data.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
// Call on page load
|
||||
ticket_collision_detection();
|
||||
|
||||
// Run every 2 mins
|
||||
setInterval(ticket_collision_detection, 120*1000);
|
||||
@@ -1,40 +0,0 @@
|
||||
// Ticket merging
|
||||
|
||||
// Gets details of the ticket we're going to merge this ticket into
|
||||
// Shows the details under the comments box & enables the merge button if the status of the merge into ticket is not closed
|
||||
function merge_into_number_get_details() {
|
||||
|
||||
// Get the ticket number to merge into
|
||||
var merge_into_ticket_number = document.getElementById("merge_into_ticket_number").value;
|
||||
|
||||
// Reset the form
|
||||
document.getElementById("merge_ticket_btn").disabled = true;
|
||||
document.getElementById("merge_into_details_div").hidden = true;
|
||||
|
||||
// Send a GET request to post.php as post.php?merge_ticket_get_json_details=true&merge_into_ticket_number=NUMBER
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{merge_ticket_get_json_details: 'true', merge_into_ticket_number: merge_into_ticket_number},
|
||||
function(data){
|
||||
// If we get a response from post.php, parse it as JSON
|
||||
const merge_into_ticket_info = JSON.parse(data);
|
||||
|
||||
// Check that the current ticket ID isn't also the new/merge ticket ID
|
||||
if(parseInt(merge_into_ticket_info.ticket_id) !== parseInt(document.getElementById("current_ticket_id").value)){
|
||||
|
||||
// Show the div with the parent ("master") ticket details, populate
|
||||
document.getElementById("merge_into_details_div").hidden = false;
|
||||
document.getElementById("merge_into_details_number").innerText = "Parent ticket details: " + merge_into_ticket_info.ticket_prefix + merge_into_ticket_info.ticket_number;
|
||||
document.getElementById("merge_into_details_client").innerText = "Client Contact: " + merge_into_ticket_info.client_name + " / " + merge_into_ticket_info.contact_name;
|
||||
document.getElementById("merge_into_details_subject").innerText = "Subject: " + merge_into_ticket_info.ticket_subject;
|
||||
document.getElementById("merge_into_details_priority").innerText = "Priority: " + merge_into_ticket_info.ticket_priority;
|
||||
document.getElementById("merge_into_details_status").innerText = "Status: " + merge_into_ticket_info.ticket_status_name;
|
||||
|
||||
// Enable the merge button if the merge into ticket isn't in a closed state
|
||||
if(merge_into_ticket_info.ticket_status_name.toLowerCase() != "closed"){
|
||||
document.getElementById("merge_ticket_btn").disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
(function() {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Initialize variables
|
||||
var timerInterval = null;
|
||||
var ticketID = getCurrentTicketID();
|
||||
var elapsedSecs = getElapsedSeconds();
|
||||
|
||||
function getCurrentTicketID() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get('ticket_id');
|
||||
}
|
||||
|
||||
function getLocalStorageKey(suffix) {
|
||||
return ticketID + "-" + suffix;
|
||||
}
|
||||
|
||||
function getElapsedSeconds() {
|
||||
let storedStartTime = parseInt(localStorage.getItem(getLocalStorageKey("startTime")) || "0");
|
||||
let pausedTime = parseInt(localStorage.getItem(getLocalStorageKey("pausedTime")) || "0");
|
||||
if (!storedStartTime) return pausedTime;
|
||||
let timeSinceStart = Math.floor((Date.now() - storedStartTime) / 1000);
|
||||
return pausedTime + timeSinceStart;
|
||||
}
|
||||
|
||||
function displayTime() {
|
||||
let totalSeconds = elapsedSecs;
|
||||
let hours = Math.floor(totalSeconds / 3600);
|
||||
totalSeconds %= 3600;
|
||||
let minutes = Math.floor(totalSeconds / 60);
|
||||
let seconds = totalSeconds % 60;
|
||||
|
||||
document.getElementById("hours").value = pad(hours);
|
||||
document.getElementById("minutes").value = pad(minutes);
|
||||
document.getElementById("seconds").value = pad(seconds);
|
||||
}
|
||||
|
||||
function pad(val) {
|
||||
return val < 10 ? "0" + val : val;
|
||||
}
|
||||
|
||||
function countTime() {
|
||||
elapsedSecs++;
|
||||
displayTime();
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
if (!localStorage.getItem(getLocalStorageKey("startTime"))) {
|
||||
localStorage.setItem(getLocalStorageKey("startTime"), Date.now().toString());
|
||||
}
|
||||
timerInterval = setInterval(countTime, 1000);
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-pause'></i>";
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "true");
|
||||
}
|
||||
|
||||
function pauseTimer() {
|
||||
if (timerInterval) {
|
||||
clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
}
|
||||
let currentElapsed = getElapsedSeconds();
|
||||
localStorage.setItem(getLocalStorageKey("pausedTime"), currentElapsed.toString());
|
||||
localStorage.removeItem(getLocalStorageKey("startTime"));
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "false");
|
||||
}
|
||||
|
||||
function clearTimeStorage() {
|
||||
localStorage.removeItem(getLocalStorageKey("startTime"));
|
||||
localStorage.removeItem(getLocalStorageKey("pausedTime"));
|
||||
localStorage.removeItem("ticket-timer-running-" + ticketID);
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
if (confirm("Are you sure you want to reset the timer?")) {
|
||||
clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
elapsedSecs = 0;
|
||||
clearTimeStorage();
|
||||
displayTime();
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
}
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "false");
|
||||
}
|
||||
|
||||
function forceResetTimer() {
|
||||
clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
elapsedSecs = 0;
|
||||
clearTimeStorage();
|
||||
displayTime();
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
}
|
||||
|
||||
function handleInputFocus() {
|
||||
pauseTimer();
|
||||
}
|
||||
|
||||
function updateTimeFromInput() {
|
||||
const hours = parseInt(document.getElementById("hours").value, 10) || 0;
|
||||
const minutes = parseInt(document.getElementById("minutes").value, 10) || 0;
|
||||
const seconds = parseInt(document.getElementById("seconds").value, 10) || 0;
|
||||
elapsedSecs = (hours * 3600) + (minutes * 60) + seconds;
|
||||
|
||||
if (!timerInterval) {
|
||||
localStorage.setItem(getLocalStorageKey("pausedTime"), elapsedSecs.toString());
|
||||
} else {
|
||||
const newStartTime = Date.now() - (elapsedSecs * 1000);
|
||||
localStorage.setItem(getLocalStorageKey("startTime"), newStartTime.toString());
|
||||
localStorage.removeItem(getLocalStorageKey("pausedTime"));
|
||||
}
|
||||
}
|
||||
|
||||
function checkStatusAndPauseTimer() {
|
||||
var status = document.querySelector('select[name="status"]').value;
|
||||
if (status.includes("Pending") || status.includes("Close")) {
|
||||
pauseTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Attach input listeners
|
||||
document.getElementById("hours").addEventListener('change', updateTimeFromInput);
|
||||
document.getElementById("minutes").addEventListener('change', updateTimeFromInput);
|
||||
document.getElementById("seconds").addEventListener('change', updateTimeFromInput);
|
||||
|
||||
document.getElementById("hours").addEventListener('focus', handleInputFocus);
|
||||
document.getElementById("minutes").addEventListener('focus', handleInputFocus);
|
||||
document.getElementById("seconds").addEventListener('focus', handleInputFocus);
|
||||
|
||||
document.querySelector('select[name="status"]').addEventListener('change', checkStatusAndPauseTimer);
|
||||
|
||||
document.getElementById("startStopTimer").addEventListener('click', function() {
|
||||
if (timerInterval === null) {
|
||||
startTimer();
|
||||
} else {
|
||||
pauseTimer();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("resetTimer").addEventListener('click', function() {
|
||||
resetTimer();
|
||||
});
|
||||
|
||||
document.getElementById("ticket_add_reply").addEventListener('click', function() {
|
||||
setTimeout(forceResetTimer, 100);
|
||||
});
|
||||
|
||||
document.getElementById("ticket_close").addEventListener('click', function() {
|
||||
setTimeout(clearTimeStorage, 100);
|
||||
});
|
||||
|
||||
// Final initialization logic
|
||||
try {
|
||||
displayTime();
|
||||
|
||||
// If no timer state, respect ticketAutoStart
|
||||
if (!localStorage.getItem(getLocalStorageKey("startTime")) && !localStorage.getItem(getLocalStorageKey("pausedTime"))) {
|
||||
if (ticketAutoStart === 1) {
|
||||
startTimer();
|
||||
} else {
|
||||
pauseTimer();
|
||||
}
|
||||
}
|
||||
// If timer already running, resume it
|
||||
else if (localStorage.getItem(getLocalStorageKey("startTime"))) {
|
||||
startTimer();
|
||||
}
|
||||
|
||||
// Check and pause timer if status is pending
|
||||
checkStatusAndPauseTimer();
|
||||
|
||||
} catch (error) {
|
||||
console.error("There was an issue initializing the timer:", error);
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -1,176 +0,0 @@
|
||||
// Used to populate dynamic content in recurring_ticket_add_modal and ticket_add_modal_v2 based on selected client
|
||||
|
||||
// Client selected listener
|
||||
// We seem to have to use jQuery to listen for events, as the client input is a select2 component?
|
||||
|
||||
const clientSelectDropdown = document.getElementById("changeClientSelect"); // Define client selector
|
||||
|
||||
// // If the client selector is disabled, we must be on a client-specific page instead. Trigger the lists to update.
|
||||
if (clientSelectDropdown.disabled) {
|
||||
|
||||
let client_id = $(clientSelectDropdown).find(':selected').val();
|
||||
|
||||
populateLists(client_id);
|
||||
}
|
||||
|
||||
// Listener for client selection. Populate select lists when a client is selected
|
||||
$(clientSelectDropdown).on('select2:select', function (e) {
|
||||
let client_id = $(this).find(':selected').val();
|
||||
|
||||
// Update the contacts dropdown list
|
||||
populateLists(client_id);
|
||||
|
||||
});
|
||||
|
||||
// Populates dropdowns with dynamic content based on the client ID
|
||||
// Called the client select dropdown is used or if the client select is disabled
|
||||
function populateLists(client_id) {
|
||||
|
||||
populateContactsDropdown(client_id);
|
||||
|
||||
populateAssetsDropdown(client_id);
|
||||
|
||||
populateLocationsDropdown(client_id);
|
||||
|
||||
populateVendorsDropdown(client_id);
|
||||
}
|
||||
|
||||
// Populate client contacts
|
||||
function populateContactsDropdown(client_id) {
|
||||
// Send a GET request to ajax.php as ajax.php?get_client_contacts=true&client_id=NUM
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_contacts: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for contacts (multiple)
|
||||
const contacts = response.contacts;
|
||||
|
||||
// Contacts dropdown
|
||||
const contactSelectDropdown = document.getElementById("contactSelect");
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = contactSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
contactSelectDropdown.remove(i);
|
||||
}
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option('- Contact -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
contacts.forEach(contact => {
|
||||
var appendText = "";
|
||||
if (contact.contact_primary == "1") {
|
||||
appendText = " (Primary)";
|
||||
} else if (contact.contact_technical == "1") {
|
||||
appendText = " (Technical)";
|
||||
}
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option(contact.contact_name + appendText, contact.contact_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client assets
|
||||
function populateAssetsDropdown(client_id) {
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_assets: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for assets (multiple)
|
||||
const assets = response.assets;
|
||||
|
||||
// Assets dropdown
|
||||
const assetSelectDropdown = document.getElementById("assetSelect");
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = assetSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
assetSelectDropdown.remove(i);
|
||||
}
|
||||
assetSelectDropdown[assetSelectDropdown.length] = new Option('- Asset -', '0');
|
||||
|
||||
// Populate dropdown with asset name (and contact, if set)
|
||||
assets.forEach(asset => {
|
||||
let displayText = asset.asset_name;
|
||||
if (asset.contact_name !== null) {
|
||||
displayText = asset.asset_name + " - " + asset.contact_name;
|
||||
}
|
||||
|
||||
assetSelectDropdown[assetSelectDropdown.length] = new Option(displayText, asset.asset_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client locations
|
||||
function populateLocationsDropdown(client_id) {
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_locations: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for locations (multiple)
|
||||
const locations = response.locations;
|
||||
|
||||
// Locations dropdown
|
||||
const locationSelectDropdown = document.getElementById("locationSelect");
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = locationSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
locationSelectDropdown.remove(i);
|
||||
}
|
||||
locationSelectDropdown[locationSelectDropdown.length] = new Option('- Location -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
locations.forEach(location => {
|
||||
locationSelectDropdown[locationSelectDropdown.length] = new Option(location.location_name, location.location_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client vendors
|
||||
function populateVendorsDropdown(client_id) {
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_vendors: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for locations (multiple)
|
||||
const vendors = response.vendors;
|
||||
|
||||
// Locations dropdown
|
||||
const vendorSelectDropdown = document.getElementById("vendorSelect");
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = vendorSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
vendorSelectDropdown.remove(i);
|
||||
}
|
||||
vendorSelectDropdown[vendorSelectDropdown.length] = new Option('- Vendor -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
vendors.forEach(vendor => {
|
||||
vendorSelectDropdown[vendorSelectDropdown.length] = new Option(vendor.vendor_name, vendor.vendor_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
console.log('CONFIG_TICKET_MOVING_COLUMNS:', CONFIG_TICKET_MOVING_COLUMNS);
|
||||
console.log('CONFIG_TICKET_ORDERING:', CONFIG_TICKET_ORDERING);
|
||||
|
||||
// -------------------------------
|
||||
// Drag: Kanban Columns (Statuses)
|
||||
// -------------------------------
|
||||
new Sortable(document.querySelector('#kanban-board'), {
|
||||
animation: 150,
|
||||
handle: '.panel-title',
|
||||
draggable: '.kanban-column',
|
||||
onEnd: function () {
|
||||
const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
|
||||
status_id: $(col).data('status-id'),
|
||||
status_kanban: index
|
||||
}));
|
||||
|
||||
if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
|
||||
$.post('ajax.php', {
|
||||
update_kanban_status_position: true,
|
||||
positions: columnPositions
|
||||
}).done(() => {
|
||||
console.log('Ticket status kanban orders updated.');
|
||||
}).fail((xhr) => {
|
||||
console.error('Error updating status order:', xhr.responseText);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// -------------------------------
|
||||
// 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()) {
|
||||
$('.drag-handle-class').css('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;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user