// UI utilities and common functions
// Page navigation
function showPage(pageId) {
// Hide all pages
const pages = document.querySelectorAll('.page');
pages.forEach(page => {
page.style.display = 'none';
});
// Show the selected page
const targetPage = document.getElementById(pageId + 'Page');
if (targetPage) {
targetPage.style.display = 'block';
// Update URL hash
window.location.hash = pageId;
// Update navigation active state
updateNavActiveState(pageId);
// Load page data if needed
loadPageData(pageId);
}
}
// Update navigation active state
function updateNavActiveState(activePageId) {
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
navLinks.forEach(link => {
link.classList.remove('active');
const onclick = link.getAttribute('onclick');
if (onclick && onclick.includes(`'${activePageId}'`)) {
link.classList.add('active');
}
});
}
// Load page-specific data
function loadPageData(pageId) {
switch (pageId) {
case 'config':
initializeConfigForm();
break;
case 'images':
loadImages();
break;
case 'teams':
loadTeams();
break;
case 'users':
loadUsers();
break;
case 'api-keys':
loadApiKeys();
break;
case 'search':
initializeSearchForm();
break;
}
}
// Alert system
function showAlert(message, type = 'info', persistent = false) {
const alertContainer = document.getElementById('alertContainer');
const alertId = 'alert-' + Date.now();
const alertHtml = `
${message}
`;
alertContainer.insertAdjacentHTML('beforeend', alertHtml);
// Auto-dismiss non-persistent alerts
if (!persistent) {
setTimeout(() => {
const alertElement = document.getElementById(alertId);
if (alertElement) {
const bsAlert = new bootstrap.Alert(alertElement);
bsAlert.close();
}
}, 5000);
}
}
// Clear all alerts
function clearAlerts() {
const alertContainer = document.getElementById('alertContainer');
alertContainer.innerHTML = '';
}
// Modal utilities
function createModal(id, title, body, footer = '') {
const modalHtml = `
${body}
${footer ? `` : ''}
`;
const modalContainer = document.getElementById('modalContainer');
modalContainer.insertAdjacentHTML('beforeend', modalHtml);
return new bootstrap.Modal(document.getElementById(id));
}
// Remove modal from DOM
function removeModal(id) {
const modal = document.getElementById(id);
if (modal) {
modal.remove();
}
}
// Loading state utilities
function setLoadingState(element, loading = true) {
if (loading) {
element.disabled = true;
element.dataset.originalText = element.innerHTML;
element.innerHTML = ' Loading...';
} else {
element.disabled = false;
element.innerHTML = element.dataset.originalText || element.innerHTML;
}
}
// Format date for display
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
}
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Truncate text
function truncateText(text, maxLength = 100) {
if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + '...';
}
// Escape HTML
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Confirm dialog
function confirmAction(message, callback) {
if (confirm(message)) {
callback();
}
}
// Copy to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
showAlert('Copied to clipboard!', 'success');
} catch (err) {
console.error('Failed to copy: ', err);
showAlert('Failed to copy to clipboard', 'danger');
}
}
// Initialize tooltips
function initializeTooltips() {
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
}
// Initialize popovers
function initializePopovers() {
const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
}
// Handle file drag and drop
function setupFileDropZone(element, callback) {
element.addEventListener('dragover', (e) => {
e.preventDefault();
element.classList.add('dragover');
});
element.addEventListener('dragleave', (e) => {
e.preventDefault();
element.classList.remove('dragover');
});
element.addEventListener('drop', (e) => {
e.preventDefault();
element.classList.remove('dragover');
const files = Array.from(e.dataTransfer.files);
callback(files);
});
}
// Validate file type and size
function validateFile(file, allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], maxSize = 10 * 1024 * 1024) {
if (!allowedTypes.includes(file.type)) {
throw new Error(`File type ${file.type} is not allowed. Allowed types: ${allowedTypes.join(', ')}`);
}
if (file.size > maxSize) {
throw new Error(`File size ${formatFileSize(file.size)} exceeds maximum allowed size of ${formatFileSize(maxSize)}`);
}
return true;
}
// Create image preview
function createImagePreview(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// Handle hash changes for navigation
window.addEventListener('hashchange', () => {
const hash = window.location.hash.substring(1);
if (hash) {
showPage(hash);
}
});
// Initialize page on load
document.addEventListener('DOMContentLoaded', () => {
// Initialize tooltips and popovers
initializeTooltips();
initializePopovers();
// Update navigation state
updateNavigationState();
// Show initial page
const hash = window.location.hash.substring(1);
const initialPage = hash || 'home';
showPage(initialPage);
});