mirror of
https://github.com/LD-Reborn/Berufsschule_HAM.git
synced 2025-12-20 06:51:55 +00:00
304 lines
9.7 KiB
JavaScript
304 lines
9.7 KiB
JavaScript
function createToastContainer() {
|
|
const container = document.createElement('div');
|
|
container.id = 'toastContainer';
|
|
container.className = 'toast-container position-fixed bottom-0 end-0 p-3';
|
|
document.body.appendChild(container);
|
|
return container;
|
|
}
|
|
|
|
// Simple toast helper
|
|
function showToast(message, type) {
|
|
const toastContainer = document.getElementById('toastContainer') || createToastContainer();
|
|
const toast = document.createElement('div');
|
|
toast.className = `toast align-items-center text-white bg-${type} border-0`;
|
|
toast.role = 'alert';
|
|
toast.innerHTML = `
|
|
<div class="d-flex">
|
|
<div class="toast-body">${message}</div>
|
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
|
|
</div>
|
|
`;
|
|
toastContainer.appendChild(toast);
|
|
const bsToast = new bootstrap.Toast(toast, { delay: 3000 });
|
|
bsToast.show();
|
|
toast.addEventListener('hidden.bs.toast', () => toast.remove());
|
|
}
|
|
|
|
function downloadBarcode(svgId, filename = "barcode.png") {
|
|
const svg = document.getElementById(svgId);
|
|
const serializer = new XMLSerializer();
|
|
const svgString = serializer.serializeToString(svg);
|
|
|
|
const canvas = document.createElement("canvas");
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
// Optionally set canvas size
|
|
const bbox = svg.getBBox();
|
|
canvas.width = bbox.width + 20; // padding
|
|
canvas.height = bbox.height + 20;
|
|
|
|
const img = new Image();
|
|
const svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
|
|
const url = URL.createObjectURL(svgBlob);
|
|
|
|
img.onload = () => {
|
|
ctx.drawImage(img, 0, 0);
|
|
URL.revokeObjectURL(url);
|
|
|
|
const pngUrl = canvas.toDataURL("image/png");
|
|
const a = document.createElement("a");
|
|
a.href = pngUrl;
|
|
a.download = filename;
|
|
a.click();
|
|
};
|
|
|
|
img.src = url;
|
|
}
|
|
|
|
function printBarcode(svgId) {
|
|
const svg = document.getElementById(svgId);
|
|
if (!svg) return;
|
|
|
|
// Serialize the SVG
|
|
const serializer = new XMLSerializer();
|
|
const svgString = serializer.serializeToString(svg);
|
|
|
|
// Open a new window for printing
|
|
const printWindow = window.open('', '_blank');
|
|
printWindow.document.write(`
|
|
<html>
|
|
<head>
|
|
<title>Print Barcode</title>
|
|
<style>
|
|
body { text-align: center; margin: 0; padding: 20px; }
|
|
svg { width: 300px; height: auto; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
${svgString}
|
|
</body>
|
|
</html>
|
|
`);
|
|
printWindow.document.close();
|
|
printWindow.focus();
|
|
printWindow.print();
|
|
printWindow.close();
|
|
}
|
|
|
|
function getBarcodeValue(BARCODE_TYPE, assetId) {
|
|
if (!assetId) return "";
|
|
const type = BARCODE_TYPE.toUpperCase();
|
|
|
|
if (type === "EAN13") {
|
|
let numeric = assetId.replace(/\D/g, "");
|
|
if (numeric.length < 12) {
|
|
numeric = numeric.padStart(12, "0");
|
|
} else if (numeric.length > 12) {
|
|
numeric = numeric.slice(0, 12);
|
|
}
|
|
return numeric;
|
|
} else if (type === "EAN8") {
|
|
let numeric = assetId.replace(/\D/g, "");
|
|
if (numeric.length < 7) {
|
|
numeric = numeric.padStart(7, "0");
|
|
} else if (numeric.length > 7) {
|
|
numeric = numeric.slice(0, 7);
|
|
}
|
|
return numeric;
|
|
} else if (type === "UPC") {
|
|
let numeric = assetId.replace(/\D/g, "");
|
|
if (numeric.length < 11) {
|
|
numeric = numeric.padStart(11, "0");
|
|
} else if (numeric.length > 11) {
|
|
numeric = numeric.slice(0, 11);
|
|
}
|
|
return numeric;
|
|
} else if (type === "ITF14") {
|
|
let numeric = assetId.replace(/\D/g, "");
|
|
if (numeric.length < 13) {
|
|
numeric = numeric.padStart(13, "0");
|
|
} else if (numeric.length > 13) {
|
|
numeric = numeric.slice(0, 13);
|
|
}
|
|
return numeric;
|
|
} else if (type === "PHARMACODE") {
|
|
let numeric = assetId.replace(/\D/g, "");
|
|
if (numeric.length < 2) {
|
|
numeric = numeric.padStart(6, "0");
|
|
} else if (numeric.length > 6) {
|
|
numeric = numeric.slice(0, 6);
|
|
}
|
|
return numeric;
|
|
}
|
|
|
|
return assetId.toString().padStart(12, "0");
|
|
}
|
|
|
|
// Table filter
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const filters = document.querySelectorAll('.column-filter');
|
|
const table = document.querySelector('table');
|
|
if (table == null) {
|
|
return;
|
|
}
|
|
const tbody = table.querySelector('tbody');
|
|
|
|
filters.forEach(filter => {
|
|
filter.addEventListener('input', () => {
|
|
const rows = tbody.querySelectorAll('tr');
|
|
const filterValues = Array.from(filters).map(f => f.value.toLowerCase().trim());
|
|
|
|
rows.forEach(row => {
|
|
const cells = row.querySelectorAll('td');
|
|
let visible = true;
|
|
|
|
filterValues.forEach((val, i) => {
|
|
if (val && !cells[i].textContent.toLowerCase().includes(val)) {
|
|
visible = false;
|
|
}
|
|
});
|
|
|
|
row.style.display = visible ? '' : 'none';
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
async function loadLocationsIntoSelect(selectElement, selectedValue = null) {
|
|
try {
|
|
const response = await fetch('/Locations/GetAll');
|
|
const data = await response.json();
|
|
const locations = data.locations;
|
|
|
|
const ts = selectElement.tomselect;
|
|
|
|
if (!ts) {
|
|
selectElement.innerHTML = `<option value="">${appTranslations.selectLocation}</option>`;
|
|
locations.forEach(loc => {
|
|
const option = document.createElement('option');
|
|
option.value = loc.location;
|
|
option.textContent = loc.location;
|
|
if (selectedValue && selectedValue === loc.location) {
|
|
option.selected = true;
|
|
}
|
|
selectElement.appendChild(option);
|
|
});
|
|
return;
|
|
}
|
|
|
|
ts.clearOptions();
|
|
ts.addOption(locations.map(loc => ({
|
|
value: loc.location,
|
|
text: loc.location
|
|
})));
|
|
ts.refreshOptions(false);
|
|
|
|
if (selectedValue) {
|
|
ts.setValue(selectedValue);
|
|
} else {
|
|
ts.clear(true);
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error('Error loading locations:', err);
|
|
showToast(appTranslations.errorLoadingLocations, 'danger');
|
|
}
|
|
}
|
|
|
|
async function loadUsersIntoSelect(selectElement, selectedValue = null) {
|
|
try {
|
|
const response = await fetch('/Users/GetAll?Cn=false&Sn=false&Title=false&Description=false&JpegPhoto=false&UserPassword=false');
|
|
const users = await response.json();
|
|
|
|
const ts = selectElement.tomselect;
|
|
if (!ts) {
|
|
selectElement.innerHTML = `<option value="">${appTranslations.selectUser}</option>`;
|
|
users.forEach(u => {
|
|
const opt = document.createElement('option');
|
|
opt.value = u.uid;
|
|
opt.textContent = u.uid;
|
|
selectElement.appendChild(opt);
|
|
});
|
|
return;
|
|
}
|
|
|
|
ts.clearOptions();
|
|
ts.addOption(users.map(u => ({ value: u.uid, text: u.uid })));
|
|
ts.refreshOptions(false);
|
|
|
|
if (selectedValue) ts.setValue(selectedValue);
|
|
} catch (err) {
|
|
console.error('Error loading users:', err);
|
|
showToast(appTranslations.errorLoadingUsers, 'danger');
|
|
}
|
|
}
|
|
|
|
function validatePassword(password) {
|
|
// Regex: min 8 chars, one uppercase, one lowercase, one number, one special char
|
|
const strongPasswordRegex =
|
|
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_\-+=\[{\]};:'",<.>/?\\|`~]).{8,}$/;
|
|
return strongPasswordRegex.test(password);
|
|
}
|
|
|
|
function unflatten(obj) {
|
|
const result = {};
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
const parts = key.split(".");
|
|
let current = result;
|
|
for (let i = 0; i < parts.length; i++) {
|
|
const part = parts[i];
|
|
if (i === parts.length - 1) {
|
|
if (typeof value === "string" && /^[\[{]/.test(value.trim())) {
|
|
try {
|
|
current[part] = JSON.parse(value);
|
|
} catch {
|
|
current[part] = value;
|
|
}
|
|
} else {
|
|
current[part] = value;
|
|
}
|
|
} else {
|
|
current[part] = current[part] || {};
|
|
current = current[part];
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
async function loadPresetsIntoSelect(selectElement, selectedValue = null) {
|
|
try {
|
|
const response = await fetch('/Settings/Presets');
|
|
const responseJson = await response.json();
|
|
var presets = [];
|
|
for (var key in responseJson) {
|
|
presets.push(key);
|
|
}
|
|
console.log(presets);
|
|
const ts = selectElement.tomselect;
|
|
if (!ts) {
|
|
selectElement.innerHTML = `<option value="">${appTranslations.selectPreset}</option>`;
|
|
presets.forEach(u => {
|
|
const opt = document.createElement('option');
|
|
opt.value = u;
|
|
opt.textContent = u;
|
|
selectElement.appendChild(opt);
|
|
});
|
|
return;
|
|
}
|
|
|
|
ts.clearOptions();
|
|
ts.addOption(presets.map(u => ({ value: u, text: u })));
|
|
ts.refreshOptions(false);
|
|
|
|
if (selectedValue) ts.setValue(selectedValue);
|
|
} catch (err) {
|
|
console.error('Error loading presets:', err);
|
|
showToast(appTranslations.errorLoadingPresets, 'danger');
|
|
}
|
|
} |