1332 lines
57 KiB
PHP
1332 lines
57 KiB
PHP
<?php
|
|
if (!defined('APP_INIT')) {
|
|
exit;
|
|
}
|
|
|
|
if (isset($this->jsScriptLoadData['form'])) { ?>
|
|
<!-- Select2 -->
|
|
<script src="/src/js/plugin/select2/select2.full.min.js"></script><!-- Bootstrap Tagsinput -->
|
|
<script src="/src/js/plugin/bootstrap-tagsinput/bootstrap-tagsinput.min.js"></script><!-- jQuery Moment.JS -->
|
|
<script src="/src/js/plugin/moment/moment.min.js"></script><!-- Bootstrap datetimepicker -->
|
|
<script src="/src/js/plugin/bootstrap-datetimepicker/bootstrap-datetimepicker.min.js"></script><!-- valicate forms -->
|
|
<script src="/src/js/plugin/jquery.validate/jquery.validate.min.js"></script><!-- dropzone -->
|
|
<script src="/src/js/plugin/dropzone/dropzone.min.js"></script>
|
|
|
|
<script>
|
|
$("#FormValidation").validate({
|
|
highlight: function (element) {
|
|
$(element).closest(".form-group").removeClass("has-success").addClass("has-error");
|
|
},
|
|
success: function (element) {
|
|
$(element).closest(".form-group").removeClass("has-error").addClass("has-success");
|
|
},
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['datatables'])) { ?>
|
|
<script src="/src/js/plugin/datatables/datatables.min.js"></script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['codeblocks'])) { ?>
|
|
<link rel="stylesheet" href="/src/css/prism.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-json.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs/plugins/toolbar/prism-toolbar.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/toolbar/prism-toolbar.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
|
<?php } ?>
|
|
|
|
|
|
<?php
|
|
# Filter datatables
|
|
if (isset($this->jsScriptLoadData['multiFilterSelect'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
$(".multi-filter-select").each(function () {
|
|
const $tableEl = $(this);
|
|
const skipColumnsAttr = $tableEl.data("skip-columns");
|
|
const skipColumns = skipColumnsAttr
|
|
? skipColumnsAttr.toString().split(',').map(Number)
|
|
: [];
|
|
const orderAttr = $tableEl.attr("data-datatables-order");
|
|
const orderConfig = orderAttr ? JSON.parse(orderAttr) : [[0, 'asc']];
|
|
|
|
const pageLengthAttr = $tableEl.attr("data-page-length");
|
|
const pageLength = pageLengthAttr ? parseInt(pageLengthAttr, 10) : 10;
|
|
let table = $tableEl.DataTable({
|
|
pageLength: pageLength,
|
|
dom: "<'row'<'col-sm-12 col-md-9'f><'pl-3 col-sm-12 col-md-3'l>>" +
|
|
"<'row'<'col-sm-12'tr>>" +
|
|
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
|
|
language: {
|
|
search: "",
|
|
lengthMenu: "Entries _MENU_"
|
|
},
|
|
order: orderConfig,
|
|
initComplete: function () {
|
|
this.api().columns().every(function (index) {
|
|
if (skipColumns.includes(index)) {
|
|
return;
|
|
}
|
|
|
|
var column = this;
|
|
|
|
var select = $('<select class="form-select"><option value=""></option></select>')
|
|
.appendTo($(column.footer()).empty())
|
|
.on('change', function () {
|
|
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
|
|
|
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
|
});
|
|
|
|
// Collect unique filter values
|
|
let uniqueValues = new Set();
|
|
|
|
column.nodes().each(function (cell) {
|
|
const cleanText = $(cell).data("filter") || $(cell).text().trim();
|
|
|
|
if (cleanText !== "") {
|
|
uniqueValues.add(cleanText);
|
|
}
|
|
});
|
|
|
|
// Sort + append unique values
|
|
Array.from(uniqueValues).sort().forEach(function (val) {
|
|
select.append('<option value="' + val + '">' + val + '</option>');
|
|
});
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
// Customize search input
|
|
$tableEl.closest('.dataTables_wrapper').find('[type=search]').each(function () {
|
|
$(this).attr("placeholder", "<?php echo __('search_') ?>");
|
|
$(this).before('<span class="fa fa-search"></span>');
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// multipleselect loading
|
|
if (isset($this->jsScriptLoadData['multiple_select'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Initialize select2 for all elements with data-multiple-select
|
|
document.querySelectorAll("[data-multiple-select]").forEach(select => {
|
|
$(select).select2({
|
|
theme: "bootstrap"
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// Function to generate a random password
|
|
if (isset($this->jsScriptLoadData['Generatepassword'])) { ?>
|
|
<script>
|
|
function generateRandomPassword(length) {
|
|
var charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_-+=<>?";
|
|
var password = "";
|
|
for (var i = 0; i < length; i++) {
|
|
var randomIndex = Math.floor(Math.random() * charset.length);
|
|
password += charset.charAt(randomIndex);
|
|
}
|
|
return password;
|
|
}
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['passwordGenOnLoad'])) { ?>
|
|
<script>
|
|
document.querySelectorAll("[data-password-target]").forEach(input => {
|
|
const passwordLength = Math.floor(Math.random() * (25 - 13 + 1)) + 13;
|
|
const generatedPassword = generateRandomPassword(passwordLength);
|
|
input.setAttribute("value", generatedPassword);
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['passwordShowHide'])) { ?>
|
|
<script>
|
|
document.querySelectorAll(".password-toggle").forEach(button => {
|
|
button.addEventListener("click", function () {
|
|
const inputId = this.getAttribute("data-toggle-target");
|
|
const input = document.getElementById(inputId);
|
|
const icon = this.querySelector("i");
|
|
|
|
if (input.type === "password") {
|
|
input.type = "text";
|
|
icon.classList.replace("fa-eye", "fa-eye-slash");
|
|
} else {
|
|
input.type = "password";
|
|
icon.classList.replace("fa-eye-slash", "fa-eye");
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['passwordRegen'])) { ?>
|
|
<script>
|
|
document.querySelectorAll(".password-generate").forEach(button => {
|
|
button.addEventListener("click", function () {
|
|
const inputId = this.getAttribute("data-generate-target");
|
|
const input = document.getElementById(inputId);
|
|
const passwordLength = Math.floor(Math.random() * (25 - 13 + 1)) + 13;
|
|
const newPassword = generateRandomPassword(passwordLength);
|
|
input.setAttribute("value", newPassword);
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// Create an datepicker input
|
|
if (isset($this->jsScriptLoadData['datepicker'])) { ?>
|
|
<script src="/src/js/plugin/moment/moment.min.js"></script>
|
|
<script src="/src/js/plugin/datepicker/bootstrap-datetimepicker.min.js"></script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Initialize datepicker for all elements with data-datepicker
|
|
document.querySelectorAll("[data-datepicker]").forEach(input => {
|
|
$(input).datetimepicker({
|
|
format: "DD/MM/YYYY"
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// Activate the right panel and tab on refresh based on the #hash in the url
|
|
if (isset($this->jsScriptLoadData['activeTabOnRefresh'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const cardBody = document.querySelector('.card-body.activeTabOnRefresh');
|
|
const hash = window.location.hash;
|
|
|
|
let selectedTab = hash ? cardBody.querySelector(`[href="${hash}"]`) : null;
|
|
let selectedContent = hash ? cardBody.querySelector(hash) : null;
|
|
|
|
if (!selectedTab || !selectedContent) {
|
|
selectedTab = cardBody.querySelector(".nav-link");
|
|
selectedContent = cardBody.querySelector(".tab-pane");
|
|
}
|
|
|
|
if (selectedTab && selectedContent) {
|
|
cardBody.querySelectorAll('.nav-link').forEach(tab => tab.classList.remove('active'));
|
|
cardBody.querySelectorAll('.tab-pane').forEach(content => content.classList.remove('show', 'active'));
|
|
selectedTab.classList.add('active');
|
|
selectedContent.classList.add('show', 'active');
|
|
}
|
|
|
|
cardBody.querySelectorAll('.nav-link').forEach(tab => {
|
|
tab.addEventListener("click", function () {
|
|
let targetTab = this.getAttribute("href");
|
|
history.replaceState(null, null, targetTab);
|
|
});
|
|
});
|
|
|
|
cardBody.style.opacity = "1";
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['activateCompany'])) { ?>
|
|
<script>
|
|
$(document).on('click', '.btn[data-item-company-state]', function (e) {
|
|
e.preventDefault();
|
|
|
|
const btn = $(this);
|
|
|
|
const companyUuid = btn.data('item-uuid');
|
|
const currentState = btn.data('item-state'); // "active" or "imported"
|
|
const newState = (currentState === "active") ? "imported" : "active";
|
|
|
|
const url = "/api/v1/customers/companies/activate/";
|
|
const params = {
|
|
company_uuid: companyUuid,
|
|
company_state: newState,
|
|
_method: 'PUT'
|
|
};
|
|
|
|
const rootStyles = getComputedStyle(document.documentElement);
|
|
const background = rootStyles.getPropertyValue('--swal-bg')?.trim();
|
|
const color = rootStyles.getPropertyValue('--swal-text-color')?.trim();
|
|
|
|
$.post(url, params)
|
|
.done(function (response, status, jqXHR) {
|
|
|
|
if (jqXHR.status === 200) {
|
|
|
|
|
|
btn.data('item-state', newState);
|
|
btn.removeClass('btn-success btn-danger');
|
|
btn.addClass(newState === "active" ? "btn-danger" : "btn-success");
|
|
btn.find('i')
|
|
.removeClass('fa-plus fa-xmark')
|
|
.addClass(newState === "active" ? "fa-xmark" : "fa-plus");
|
|
|
|
const row = btn.closest("tr");
|
|
const stateCell = row.find("td").eq(3);
|
|
stateCell.text(newState);
|
|
}
|
|
})
|
|
.fail(function (jqXHR) {
|
|
let response = jqXHR.responseJSON || {};
|
|
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
icon: "error",
|
|
title: "<?php echo __('connection_error_title') ?>",
|
|
text: response.message || "<?php echo __('connection_error_text') ?>: " + jqXHR.status,
|
|
confirmButtonText: "<?php echo __('close') ?>",
|
|
customClass: {confirmButton: "btn btn-danger"},
|
|
buttonsStyling: false
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
if (isset($this->jsScriptLoadData['multiFilterSelectServers'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
function setCookie(name, value, days = 365) {
|
|
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
document.cookie = name + "=" + encodeURIComponent(value) + "; expires=" + expires + "; path=/";
|
|
}
|
|
|
|
$(".multi-filter-select").each(function () {
|
|
|
|
const $tableEl = $(this);
|
|
|
|
//
|
|
// AUTO-BUILD columnDefs from <th data-column="">
|
|
//
|
|
const columnDefs = [];
|
|
$tableEl.find("thead th").each(function (index) {
|
|
const colName = $(this).data("column") || "";
|
|
columnDefs.push({
|
|
targets: index,
|
|
name: colName
|
|
});
|
|
});
|
|
|
|
//
|
|
// INITIALIZE DATATABLE
|
|
//
|
|
let table = $tableEl.DataTable({
|
|
autoWidth: false,
|
|
pageLength: $tableEl.attr("data-page-length") ? parseInt($tableEl.attr("data-page-length"), 10) : 10,
|
|
dom: "<'row'<'col-sm-12 col-md-9'f><'pl-3 col-sm-12 col-md-3'l>>" +
|
|
"<'row'<'col-sm-12'tr>>" +
|
|
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
|
|
|
|
language: {
|
|
search: "",
|
|
lengthMenu: "Entries _MENU_"
|
|
},
|
|
order: (function () {
|
|
let idx = 0;
|
|
$tableEl.find("thead th").each(function (i) {
|
|
if ($(this).data("column") === "server_hostname") {
|
|
idx = i;
|
|
}
|
|
});
|
|
return [[idx, 'asc']];
|
|
})(),
|
|
columnDefs: columnDefs,
|
|
initComplete: function () {
|
|
|
|
const dtApi = this.api();
|
|
|
|
dtApi.columns().every(function () {
|
|
|
|
const colIndex = this.index();
|
|
const th = $tableEl.find("thead th").eq(colIndex);
|
|
const colName = th.data("column");
|
|
|
|
if (!colName) return;
|
|
|
|
const footerCell = $(this.footer());
|
|
if (!footerCell.length) return;
|
|
|
|
const select = $('<select class="form-select"><option value=""></option></select>')
|
|
.appendTo(footerCell.empty())
|
|
.on('change', function () {
|
|
const val = $.fn.dataTable.util.escapeRegex($(this).val());
|
|
dtApi.column(colName + ":name")
|
|
.search(val ? '^' + val + '$' : '', true, false)
|
|
.draw();
|
|
});
|
|
|
|
const uniqueValues = new Set();
|
|
this.nodes().each(function (cell) {
|
|
const cleanText = $(cell).data("filter") || $(cell).text().trim();
|
|
if (cleanText !== "") uniqueValues.add(cleanText);
|
|
});
|
|
|
|
Array.from(uniqueValues).sort().forEach(v => {
|
|
select.append('<option value="' + v + '">' + v + '</option>');
|
|
});
|
|
});
|
|
|
|
//
|
|
// APPLY CHECKBOX VISIBILITY DEFAULTS
|
|
//
|
|
// Set initial visibility based on checkboxes
|
|
$(".selectgroup-input").each(function () {
|
|
const baseName = $(this).val();
|
|
const visible = $(this).is(":checked");
|
|
|
|
dtApi.columns().every(function () {
|
|
const name = this.settings()[0].aoColumns[this.index()].name || '';
|
|
if (name === baseName || name.startsWith(baseName + '_')) {
|
|
this.visible(visible);
|
|
}
|
|
});
|
|
});
|
|
|
|
$(".selectgroup-input").on("change", function () {
|
|
const selected = [];
|
|
$(".selectgroup-input:checked").each(function () {
|
|
selected.push($(this).val());
|
|
});
|
|
|
|
// Save selected checkboxes in a cookie (or localStorage)
|
|
// Using localStorage here
|
|
setCookie("serverTableColumns", JSON.stringify(selected), 365);
|
|
|
|
const baseName = $(this).val();
|
|
const visible = $(this).is(":checked");
|
|
|
|
|
|
// toggle all columns whose data-column === baseName or starts with baseName + '_'
|
|
table.columns(`[data-column^='${baseName}']`).visible(visible);
|
|
});
|
|
}
|
|
});
|
|
|
|
//
|
|
// SEARCH FIELD ICON
|
|
//
|
|
$tableEl.closest('.dataTables_wrapper').find('[type=search]').each(function () {
|
|
$(this).attr("placeholder", "<?php echo __('search_') ?>");
|
|
$(this).before('<span class="fa fa-search"></span>');
|
|
});
|
|
|
|
//
|
|
// HANDLE CHECKBOX TOGGLE
|
|
//
|
|
$(".selectgroup-input").on("change", function () {
|
|
const colName = $(this).val();
|
|
table.column(colName + ":name").visible($(this).is(":checked"));
|
|
});
|
|
|
|
});
|
|
});
|
|
|
|
</script>
|
|
<?php }
|
|
if (isset($this->jsScriptLoadData['inserve_source'])) { ?>
|
|
<script>
|
|
$(document).on('click', '.test-inserve-connection-btn', function (e) {
|
|
e.preventDefault();
|
|
|
|
const url = "/api/v1/sources/inserve/";
|
|
const params = {action: "auth/me"};
|
|
const rootStyles = getComputedStyle(document.documentElement);
|
|
const background = rootStyles.getPropertyValue('--swal-bg')?.trim();
|
|
const color = rootStyles.getPropertyValue('--swal-text-color')?.trim();
|
|
|
|
$.get(url, params)
|
|
.done(function (response, status, jqXHR) {
|
|
// Check if HTTP code is 200
|
|
if (jqXHR.status === 200) {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
icon: "success",
|
|
title: "<?php echo __('connection_success_title') ?>",
|
|
text: "<?php echo __('connection_success_text') ?>",
|
|
confirmButtonText: "<?php echo __('close') ?>",
|
|
customClass: {confirmButton: "btn btn-success"},
|
|
buttonsStyling: true
|
|
});
|
|
}
|
|
})
|
|
.fail(function (jqXHR) {
|
|
let response = jqXHR.responseJSON || {};
|
|
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
icon: "error",
|
|
title: "<?php echo __('connection_error_title') ?>",
|
|
text: response.message || "<?php echo __('connection_error_text') ?>: " + jqXHR.status,
|
|
confirmButtonText: "<?php echo __('close') ?>",
|
|
customClass: {confirmButton: "btn btn-danger"},
|
|
buttonsStyling: false
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// slugify an input field
|
|
if (isset($this->jsScriptLoadData['slugify'])) { ?>
|
|
<script>
|
|
function slugify(str) {
|
|
return str
|
|
.trim()
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9 -]/g, '') // Remove non-alphanumeric characters
|
|
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
|
.replace(/-+/g, '-'); // Remove consecutive hyphens
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
document.querySelectorAll("[data-slugify]").forEach(input => {
|
|
input.addEventListener("input", function () {
|
|
const targetId = this.getAttribute("data-slugify");
|
|
const targetInput = document.getElementById(targetId);
|
|
if (targetInput) {
|
|
targetInput.value = slugify(this.value);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
// Clicking on a btn will copy the value of an input to the clipboard
|
|
if (isset($this->jsScriptLoadData['copyInputValue'])) { ?>
|
|
<script>
|
|
function copyToClipboard(inputId) {
|
|
let input = document.getElementById(inputId);
|
|
if (input) {
|
|
navigator.clipboard.writeText(input.value).then(() => {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: '<?php echo __('copied') ?>',
|
|
text: '<?php echo __('copy_text_success') ?>',
|
|
icon: 'success',
|
|
confirmButtonText: '<?php echo __('ok') ?>'
|
|
});
|
|
}).catch(err => {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: 'Error!',
|
|
text: 'Failed to copy the content.',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['CopyTargetData'])) { ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
document.querySelectorAll('[data-copy-target]').forEach(button => {
|
|
button.addEventListener('click', function () {
|
|
const targetId = this.getAttribute('data-copy-target');
|
|
const target = document.getElementById(targetId);
|
|
|
|
if (target) {
|
|
const copyData = target.getAttribute('data-copy-data');
|
|
if (copyData) {
|
|
navigator.clipboard.writeText(copyData).then(() => {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: '<?php echo __('copied') ?>',
|
|
text: '<?php echo __('copy_text_success') ?>',
|
|
icon: 'success',
|
|
confirmButtonText: '<?php echo __('ok') ?>'
|
|
});
|
|
}).catch(err => {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: 'Error!',
|
|
text: 'Failed to copy the content.',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['validateJson'])) { ?>
|
|
<script>
|
|
function isValidJSON(value) {
|
|
try {
|
|
JSON.parse(value);
|
|
return true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Attach JSON validation to all textareas with data-validate-json
|
|
document.querySelectorAll("[data-validate-json]").forEach(textarea => {
|
|
textarea.addEventListener("input", function () {
|
|
const value = this.value.trim();
|
|
const feedback = this.nextElementSibling; // Assuming <small> is right after <textarea>
|
|
|
|
if (value === "" || isValidJSON(value)) {
|
|
feedback.textContent = "<?php echo __('json_valid') ?>";
|
|
feedback.style.color = "green";
|
|
this.classList.remove("is-invalid");
|
|
this.classList.add("is-valid");
|
|
} else {
|
|
feedback.textContent = "<?php echo __('json_invalid') ?>";
|
|
feedback.style.color = "red";
|
|
this.classList.remove("is-valid");
|
|
this.classList.add("is-invalid");
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['stompjes'])) { ?>
|
|
<script src="/src/js/plugin/chart.js/chart.min.js"></script>
|
|
<script>
|
|
// Attach event listener
|
|
$(document).on('click', '.stomp-btn', function (e) {
|
|
e.preventDefault(); // Prevent default link behavior
|
|
|
|
const itemUuid = $(this).data('item-uuid');
|
|
const itemName = $(this).data('item-name')
|
|
const apiUrl = $(this).data('api-url');
|
|
const deleteAction = $(this).data('delete-action') || false;
|
|
const row = $(this).closest('tr');
|
|
|
|
const StompOptions = {
|
|
itemUuid: itemUuid,
|
|
itemName: itemName,
|
|
apiUrl: apiUrl,
|
|
row: row,
|
|
deleteAction: deleteAction,
|
|
title: "<?php echo __('action_confirm')?>",
|
|
text: "<?php echo __('action_confirm_text')?>",
|
|
icon: "question",
|
|
responseSuccessTitle: "<?php echo __('stomped')?>",
|
|
responseSuccessText: "<?php echo __('stomped_success')?>",
|
|
responseSuccessBtnText: "<?php echo __('close') ?>",
|
|
responseErrorTitle: "<?php echo __('action_error_title')?>",
|
|
responseErrorText: "<?php echo __('action_error_text')?>",
|
|
cancelConfirmTitle: "<?php echo __('action_cancel_confirm_title')?>",
|
|
cancelConfirmText: "<?php echo __('action_cancel_confirm_text')?>",
|
|
cancelConfirmBtnText: "<?php echo __('close') ?>",
|
|
};
|
|
|
|
// Make the POST request to delete the device
|
|
$.post(apiUrl, {
|
|
[itemName]: itemUuid,
|
|
_method: "POST"
|
|
})
|
|
|
|
.done(function (response) {
|
|
// Parse the response if necessary
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: StompOptions.responseSuccessTitle || "Added!",
|
|
text: response.message || StompOptions.responseSuccessText || "Your stomp has been added.",
|
|
confirmButtonText: StompOptions.responseSuccessBtnText,
|
|
icon: "success",
|
|
customClass: {
|
|
confirmButton: "btn btn-success",
|
|
},
|
|
buttonsStyling: true,
|
|
}).then((result) => {
|
|
const counterEl = $("#count-" + itemUuid);
|
|
|
|
if (counterEl.length) {
|
|
const currentCount = parseInt(counterEl.text(), 10);
|
|
if (!isNaN(currentCount)) {
|
|
counterEl.text(currentCount + 1);
|
|
}
|
|
}
|
|
});
|
|
})
|
|
.fail(function (jqXHR) {
|
|
let response = jqXHR.responseJSON || {};
|
|
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: StompOptions.responseErrorTitle,
|
|
text: response.message || StompOptions.responseErrorText,
|
|
icon: "error",
|
|
customClass: {confirmButton: "btn btn-danger"},
|
|
buttonsStyling: false,
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
// Attach event listener
|
|
$(document).on('click', '.stomp-delete-btn', function (e) {
|
|
e.preventDefault(); // Prevent default link behavior
|
|
|
|
const row = $(this).closest('tr');
|
|
|
|
const deleteStompOptions = {
|
|
itemUuid: $(this).data('item-uuid'),
|
|
itemName: $(this).data('item-name'),
|
|
apiUrl: $(this).data('api-url'),
|
|
row: row,
|
|
deleteAction: $(this).data('delete-action') || false,
|
|
title: "<?php echo __('action_confirm')?>",
|
|
text: "<?php echo __('action_confirm_text')?>",
|
|
confirmButtonText: "<?php echo __('action_confirm_button')?>",
|
|
cancelButtonText: "<?php echo __('action_cancel_button')?>",
|
|
responseSuccessTitle: "<?php echo __('deleted')?>",
|
|
responseSuccessText: "<?php echo __('action_success_text')?>",
|
|
responseSuccessBtnText: "<?php echo __('close') ?>",
|
|
responseErrorTitle: "<?php echo __('action_error_title')?>",
|
|
responseErrorText: "<?php echo __('action_error_text')?>",
|
|
cancelConfirmBtnText: "<?php echo __('close') ?>",
|
|
};
|
|
|
|
// Make the POST request to delete the device
|
|
$.post(deleteStompOptions.apiUrl, {
|
|
[deleteStompOptions.itemName]: deleteStompOptions.itemUuid,
|
|
_method: "DELETE"
|
|
})
|
|
|
|
.done(function (response) {
|
|
// Parse the response if necessary
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: deleteStompOptions.responseSuccessTitle || "Deleted!",
|
|
text: response.message || deleteStompOptions.responseSuccessText || "Your item has been deleted.",
|
|
confirmButtonText: deleteStompOptions.responseSuccessBtnText,
|
|
icon: "error",
|
|
customClass: {
|
|
confirmButton: "btn btn-danger",
|
|
},
|
|
buttonsStyling: true,
|
|
}).then((result) => {
|
|
// If deleteAction is false, remove the row; otherwise, process show and hide actions
|
|
const userUUID = deleteStompOptions.row.data('user-uuid');
|
|
const counterEl = $("#count-" + userUUID);
|
|
|
|
if (counterEl.length) {
|
|
const currentCount = parseInt(counterEl.text(), 10);
|
|
if (!isNaN(currentCount) && currentCount > 0) {
|
|
counterEl.text(currentCount - 1);
|
|
}
|
|
}
|
|
|
|
if (!deleteStompOptions.deleteAction || deleteStompOptions.deleteAction === "false") {
|
|
row.fadeOut(500, function () {
|
|
$(this).remove();
|
|
});
|
|
}
|
|
});
|
|
})
|
|
.fail(function (jqXHR) {
|
|
let response = jqXHR.responseJSON || {};
|
|
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: deleteStompOptions.responseErrorTitle,
|
|
text: response.message || deleteStompOptions.responseErrorText,
|
|
icon: "error",
|
|
customClass: {confirmButton: "btn btn-danger"},
|
|
buttonsStyling: false,
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
|
|
const gruvboxColors = [
|
|
"#fabd2f", // yellow
|
|
"#b8bb26", // green
|
|
"#fb4934", // red
|
|
"#8ec07c", // aqua
|
|
"#83a598", // blue
|
|
"#fe8019", // orange
|
|
];
|
|
|
|
const assignedColors = {};
|
|
const usedColors = new Set();
|
|
|
|
function hexToRGBA(hex, alpha) {
|
|
hex = hex.replace('#', '');
|
|
const r = parseInt(hex.substring(0, 2), 16);
|
|
const g = parseInt(hex.substring(2, 4), 16);
|
|
const b = parseInt(hex.substring(4, 6), 16);
|
|
return `rgba(${r},${g},${b},${alpha})`;
|
|
}
|
|
|
|
function getColorForUser(name) {
|
|
if (assignedColors[name]) return assignedColors[name];
|
|
|
|
let hash = 0;
|
|
for (let i = 0; i < name.length; i++) {
|
|
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
}
|
|
let preferredIndex = Math.abs(hash) % gruvboxColors.length;
|
|
let preferredColor = gruvboxColors[preferredIndex];
|
|
|
|
if (!usedColors.has(preferredColor)) {
|
|
assignedColors[name] = preferredColor;
|
|
usedColors.add(preferredColor);
|
|
return preferredColor;
|
|
}
|
|
|
|
const unused = gruvboxColors.filter(c => !usedColors.has(c));
|
|
let finalColor = unused.length > 0
|
|
? unused[Math.floor(Math.random() * unused.length)]
|
|
: gruvboxColors[Math.floor(Math.random() * gruvboxColors.length)];
|
|
|
|
assignedColors[name] = finalColor;
|
|
usedColors.add(finalColor);
|
|
return finalColor;
|
|
}
|
|
|
|
// Helper: get all dates between two dates (inclusive)
|
|
function getDatesBetween(startDate, endDate) {
|
|
const dates = [];
|
|
let current = new Date(startDate);
|
|
const end = new Date(endDate);
|
|
|
|
while (current <= end) {
|
|
dates.push(current.toISOString().slice(0, 10));
|
|
current.setDate(current.getDate() + 1);
|
|
}
|
|
return dates;
|
|
}
|
|
|
|
// Read selected date inputs (format: d/m/Y)
|
|
const fromInput = document.getElementById("fd").value.split("/");
|
|
const toInput = document.getElementById("td").value.split("/");
|
|
|
|
const fromDate = new Date(`${fromInput[2]}-${fromInput[1]}-${fromInput[0]}`);
|
|
const toDate = new Date(`${toInput[2]}-${toInput[1]}-${toInput[0]}`);
|
|
|
|
// Generate all dates in range
|
|
const sortedDates = getDatesBetween(fromDate, toDate);
|
|
|
|
const users = {};
|
|
|
|
// Populate user data
|
|
stompData.forEach(item => {
|
|
const user = item.user_first_name;
|
|
const date = new Date(item.stomp_timestamp * 1000).toISOString().slice(0, 10);
|
|
|
|
if (!users[user]) users[user] = {};
|
|
if (!users[user][date]) users[user][date] = 0;
|
|
|
|
users[user][date] += 1;
|
|
});
|
|
|
|
// Fill missing dates with 0
|
|
Object.keys(users).forEach(user => {
|
|
sortedDates.forEach(date => {
|
|
if (!users[user][date]) users[user][date] = 0;
|
|
});
|
|
});
|
|
|
|
// Build datasets
|
|
const datasets = Object.keys(users).map(user => {
|
|
const color = getColorForUser(user);
|
|
return {
|
|
label: user,
|
|
data: sortedDates.map(date => users[user][date]),
|
|
borderColor: color,
|
|
backgroundColor: hexToRGBA(color, 0.1),
|
|
tension: 0.3
|
|
};
|
|
});
|
|
|
|
// Chart config
|
|
const data = {
|
|
labels: sortedDates,
|
|
datasets: datasets
|
|
};
|
|
|
|
const config = {
|
|
type: 'line',
|
|
data: data,
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: {position: 'top'},
|
|
title: {
|
|
display: true,
|
|
text: 'Stomps per User per Day'
|
|
}
|
|
},
|
|
scales: {y: {beginAtZero: true}}
|
|
}
|
|
};
|
|
|
|
// Render chart
|
|
new Chart(document.getElementById('stompjesChart'), config);
|
|
|
|
|
|
</script>
|
|
<script>
|
|
$(document).ready(function () {
|
|
$("#datePicker").on("click", function () {
|
|
const fd = $("#fd").val(); // start date
|
|
const td = $("#td").val(); // end date
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
if (fd) params.set("fd", fd);
|
|
else params.delete("fd");
|
|
|
|
if (td) params.set("td", td);
|
|
else params.delete("td");
|
|
|
|
// Reload page with updated GET parameters
|
|
window.location.href = window.location.pathname + "?" + params.toString();
|
|
});
|
|
});
|
|
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['delete_confirmation'])) { ?>
|
|
<script>
|
|
const rootStyles = getComputedStyle(document.documentElement);
|
|
const background = rootStyles.getPropertyValue('--swal-bg')?.trim();
|
|
const color = rootStyles.getPropertyValue('--swal-text-color')?.trim();
|
|
|
|
function showDeleteConfirmation({
|
|
itemUuid,
|
|
itemName,
|
|
apiUrl,
|
|
row,
|
|
deleteAction,
|
|
title = "Are you sure?",
|
|
text = "You won't be able to revert this!",
|
|
icon = "question",
|
|
confirmButtonText = "Yes, delete",
|
|
cancelButtonText = "Cancel!",
|
|
background = getComputedStyle(document.documentElement).getPropertyValue('--swal-bg')?.trim(),
|
|
color = getComputedStyle(document.documentElement).getPropertyValue('--swal-text-color')?.trim(),
|
|
customClass = {
|
|
confirmButton: "btn btn-danger mx-2",
|
|
cancelButton: "btn btn-secondary"
|
|
},
|
|
responseSuccessTitle = '',
|
|
responseSuccessText = '',
|
|
responseSuccessBtnText = '',
|
|
responseErrorTitle = '',
|
|
responseErrorText = '',
|
|
cancelConfirmTitle = '',
|
|
cancelConfirmText = '',
|
|
cancelConfirmBtnText = ''
|
|
}) {
|
|
Swal.fire({
|
|
title: title,
|
|
text: text,
|
|
icon: icon,
|
|
background: background,
|
|
color: color,
|
|
showCancelButton: true,
|
|
confirmButtonText: confirmButtonText,
|
|
cancelButtonText: cancelButtonText,
|
|
customClass: customClass,
|
|
buttonsStyling: false,
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
// Make the POST request to delete the item
|
|
$.post(apiUrl, {
|
|
[itemName]: itemUuid,
|
|
_method: "DELETE"
|
|
})
|
|
.done(function (response) {
|
|
|
|
if (!(typeof deleteAction === "string" && deleteAction.startsWith("url:"))) { // do not fire the swal if there will be a redirect
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: responseSuccessTitle || "Deleted!",
|
|
text: response.message || responseSuccessText || "Your item has been deleted.",
|
|
confirmButtonText: responseSuccessBtnText,
|
|
icon: "success",
|
|
customClass: {
|
|
confirmButton: "btn btn-success",
|
|
},
|
|
buttonsStyling: true,
|
|
});
|
|
}
|
|
|
|
if (typeof deleteAction === "string" && deleteAction.startsWith("url:")) {
|
|
const targetUrl = deleteAction.replace("url:", "").trim();
|
|
window.location.href = targetUrl;
|
|
} else if (!deleteAction || deleteAction === "false") {
|
|
row.fadeOut(500, function () {
|
|
$(this).remove();
|
|
});
|
|
} else {
|
|
try {
|
|
let actions = typeof deleteAction === "string" ? JSON.parse(deleteAction) : deleteAction;
|
|
for (const [elementId, action] of Object.entries(actions)) {
|
|
let $element = $("#" + elementId);
|
|
|
|
if (action === "show") {
|
|
$element.fadeIn(500); // Fade in element smoothly
|
|
} else if (action === "hide") {
|
|
$element.fadeOut(0); // Fade out element smoothly
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Error parsing deleteAction JSON:", error);
|
|
}
|
|
}
|
|
})
|
|
.fail(function (jqXHR) {
|
|
// Parse the error response
|
|
let response = jqXHR.responseJSON || {};
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: responseErrorTitle || "Error",
|
|
text: response.message || responseErrorText || "An error occurred. Please contact support.",
|
|
icon: "error",
|
|
customClass: {
|
|
confirmButton: "btn btn-danger",
|
|
},
|
|
buttonsStyling: false,
|
|
});
|
|
});
|
|
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
|
Swal.fire({
|
|
background: background,
|
|
color: color,
|
|
title: cancelConfirmTitle,
|
|
text: cancelConfirmText,
|
|
confirmButtonText: cancelConfirmBtnText,
|
|
icon: "info",
|
|
customClass: {
|
|
confirmButton: "btn btn-black",
|
|
},
|
|
buttonsStyling: false,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Attach event listener
|
|
$(document).on('click', '.delete-btn', function (e) {
|
|
e.preventDefault(); // Prevent default link behavior
|
|
|
|
const itemUuid = $(this).data('item-uuid');
|
|
const itemName = $(this).data('item-name')
|
|
const apiUrl = $(this).data('api-url');
|
|
const deleteAction = $(this).data('delete-action') || false;
|
|
const row = $(this).closest('tr');
|
|
|
|
const deleteOptions = {
|
|
itemUuid: itemUuid,
|
|
itemName: itemName,
|
|
apiUrl: apiUrl,
|
|
row: row,
|
|
deleteAction: deleteAction,
|
|
title: "<?php echo __('action_confirm')?>",
|
|
text: "<?php echo __('action_confirm_text')?>",
|
|
icon: "question",
|
|
confirmButtonText: "<?php echo __('action_confirm_button')?>",
|
|
cancelButtonText: "<?php echo __('action_cancel_button')?>",
|
|
responseSuccessTitle: "<?php echo __('action_success_title')?>",
|
|
responseSuccessText: "<?php echo __('action_success_text')?>",
|
|
responseSuccessBtnText: "<?php echo __('close') ?>",
|
|
responseErrorTitle: "<?php echo __('action_error_title')?>",
|
|
responseErrorText: "<?php echo __('action_error_text')?>",
|
|
cancelConfirmTitle: "<?php echo __('action_cancel_confirm_title')?>",
|
|
cancelConfirmText: "<?php echo __('action_cancel_confirm_text')?>",
|
|
cancelConfirmBtnText: "<?php echo __('close') ?>",
|
|
};
|
|
|
|
showDeleteConfirmation(deleteOptions);
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['load_dropzone'])) { ?>
|
|
<script>
|
|
// Disable Dropzone's auto-discover feature
|
|
Dropzone.autoDiscover = false;
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
// Select all forms with the Dropzone class
|
|
const dropzones = document.querySelectorAll('.dropzone');
|
|
|
|
dropzones.forEach((form) => {
|
|
// Check if Dropzone is already attached
|
|
if (form.dropzone) return;
|
|
|
|
// Get the form type from the data attribute
|
|
const formType = form.getAttribute('data-form-type');
|
|
const associatedTable = document.querySelector(`table[data-table-type="${formType}"] tbody`);
|
|
|
|
// Initialize Dropzone for the form
|
|
new Dropzone(form, {
|
|
url: form.getAttribute('action'),
|
|
paramName: 'file', // Name of the file input
|
|
autoProcessQueue: true, // Automatically upload files when dropped
|
|
maxFilesize: 600, // Maximum file size in MB
|
|
acceptedFiles: '.pdf,.rom', // Adjust accepted files as needed
|
|
init: function () {
|
|
this.on('success', function (file, response) {
|
|
const parsedResponse = typeof response === 'string' ? JSON.parse(response) : response;
|
|
if (parsedResponse.status === 'success') {
|
|
// Check if the table and tbody exist
|
|
if (associatedTable) {
|
|
// Add the uploaded file to the corresponding table
|
|
const newRow = document.createElement('tr');
|
|
const newCell = document.createElement('td');
|
|
newCell.textContent = parsedResponse.file_name;
|
|
newRow.appendChild(newCell);
|
|
associatedTable.appendChild(newRow);
|
|
} else {
|
|
console.error('Associated table not found for form type:', formType);
|
|
}
|
|
} else {
|
|
console.error('Error uploading file:', parsedResponse.message || 'Unknown error');
|
|
}
|
|
});
|
|
|
|
this.on('error', function (file, errorMessage) {
|
|
console.error('Error uploading file:', errorMessage);
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['updateToggle'])) { ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
document.querySelectorAll('.checkbox').forEach(function (checkbox) {
|
|
checkbox.addEventListener('change', async function (e) {
|
|
const input = e.target;
|
|
const apiUrl = input.getAttribute('data-api-url');
|
|
const changeKey = input.getAttribute('data-api-changevalue');
|
|
const dataRaw = input.getAttribute('data-api-data');
|
|
|
|
let dataObj;
|
|
try {
|
|
dataObj = JSON.parse(dataRaw);
|
|
} catch (err) {
|
|
console.error('Invalid JSON in data-api-data:', err);
|
|
return;
|
|
}
|
|
|
|
// Toggle value FIRST
|
|
if (changeKey in dataObj) {
|
|
const currentValue = dataObj[changeKey];
|
|
const toggled = currentValue === '1' || currentValue === 1 ? 0 : 1;
|
|
dataObj[changeKey] = toggled;
|
|
}
|
|
|
|
// Add method override
|
|
dataObj._method = 'PUT';
|
|
|
|
// Convert to URL-encoded string
|
|
const formBody = new URLSearchParams(dataObj).toString();
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
},
|
|
body: formBody
|
|
});
|
|
|
|
if (response.ok) {
|
|
// Remove _method before saving back
|
|
delete dataObj._method;
|
|
input.setAttribute('data-api-data', JSON.stringify(dataObj));
|
|
} else {
|
|
input.checked = !input.checked; // revert toggle
|
|
console.error('Request failed:', await response.text());
|
|
}
|
|
} catch (err) {
|
|
input.checked = !input.checked;
|
|
console.error('Request error:', err);
|
|
}
|
|
|
|
});
|
|
});
|
|
});
|
|
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['updatePermissions'])) { ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
document.querySelectorAll('.checkbox').forEach(checkbox => {
|
|
checkbox.addEventListener('change', async (e) => {
|
|
const input = e.target;
|
|
|
|
const permissionUUID = input.dataset.permissionUuid;
|
|
const userGroupUUID = input.dataset.userGroupUuid;
|
|
const permissionValue = input.dataset.value;
|
|
const apiUrl = input.dataset.apiUrl;
|
|
|
|
// Revert the checkbox immediately; only mark it again on success
|
|
input.checked = !input.checked;
|
|
input.disabled = true;
|
|
|
|
// Build URL-encoded form data
|
|
const formData = new URLSearchParams();
|
|
formData.append('permission_uuid', permissionUUID);
|
|
formData.append('user_group_uuid', userGroupUUID);
|
|
formData.append('permission_value', permissionValue);
|
|
formData.append('_method', 'PUT')
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: formData.toString()
|
|
});
|
|
|
|
if (response.ok) {
|
|
// Uncheck all switches in the same group
|
|
const groupSelector = `input[data-permission-uuid="${permissionUUID}"][data-user-group-uuid="${userGroupUUID}"]`;
|
|
document.querySelectorAll(groupSelector).forEach(cb => cb.checked = false);
|
|
|
|
// Then check the selected one
|
|
input.checked = true;
|
|
} else {
|
|
console.error('API error:', response.status);
|
|
// Leave checkbox state unchanged (reverted above)
|
|
}
|
|
} catch (err) {
|
|
console.error('Network error:', err);
|
|
// Leave checkbox state unchanged (reverted above)
|
|
} finally {
|
|
input.disabled = false;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['enableButtonOnImageUpload'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const fileInputs = document.querySelectorAll('input[type="file"][data-enable-button]');
|
|
|
|
fileInputs.forEach(function (input) {
|
|
input.addEventListener("change", function () {
|
|
const buttonId = input.getAttribute("data-enable-button");
|
|
const button = document.getElementById(buttonId);
|
|
|
|
if (input.files.length > 0) {
|
|
button.removeAttribute("disabled");
|
|
button.classList.remove("opacity-0");
|
|
button.classList.add("opacity-100");
|
|
} else {
|
|
button.setAttribute("disabled", "disabled");
|
|
button.classList.remove("opacity-100");
|
|
button.classList.add("opacity-0");
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
<?php }
|
|
|
|
if (isset($this->jsScriptLoadData['breadCrumbs'])) { ?>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Access the PHP array stored in $GLOBALS['breadCrumbArray']
|
|
const breadcrumbArray = <?php echo json_encode($GLOBALS['breadCrumbArray']); ?>;
|
|
|
|
// Get the breadcrumb container
|
|
const breadcrumbContainer = document.getElementById("breadCrumb");
|
|
|
|
// Create the ul element
|
|
const ul = document.createElement("ul");
|
|
ul.classList.add("breadcrumbs", "mb-3");
|
|
|
|
// Loop through the array to generate breadcrumb items
|
|
breadcrumbArray.forEach((item, index) => {
|
|
// Create the li for each item
|
|
const li = document.createElement("li");
|
|
li.classList.add("nav-item");
|
|
|
|
// Create the anchor tag
|
|
const a = document.createElement("a");
|
|
|
|
// Check if it's the last item to make it non-clickable (active)
|
|
if (index === breadcrumbArray.length - 1) {
|
|
// This is the active page, so we remove the href and add a class
|
|
a.removeAttribute("href");
|
|
a.classList.add("active");
|
|
|
|
} else {
|
|
// For other items, set the href as usual
|
|
a.classList.add("text-info");
|
|
a.href = item.href;
|
|
}
|
|
|
|
// Insert the HTML content for the display (includes icons)
|
|
a.innerHTML = item.display; // Use innerHTML to allow icon rendering
|
|
|
|
// Append the anchor tag to the li
|
|
li.appendChild(a);
|
|
|
|
// Append the li to the ul
|
|
ul.appendChild(li);
|
|
|
|
// Add separator if not the last item
|
|
if (index < breadcrumbArray.length - 1) {
|
|
const separator = document.createElement("li");
|
|
separator.classList.add("separator");
|
|
|
|
// Create Font Awesome icon
|
|
const arrowIcon = document.createElement("i");
|
|
arrowIcon.classList.add("fa-solid", "fa-chevron-right");
|
|
|
|
separator.appendChild(arrowIcon);
|
|
ul.appendChild(separator);
|
|
}
|
|
});
|
|
|
|
// Append the generated breadcrumb to the breadcrumb container
|
|
breadcrumbContainer.appendChild(ul);
|
|
});
|
|
</script>
|
|
<?php } ?>
|