356 lines
12 KiB
JavaScript
356 lines
12 KiB
JavaScript
// UI utilities and common functions
|
|
|
|
// Page navigation
|
|
function showPage(pageId) {
|
|
try {
|
|
console.log('=== showPage called with pageId:', pageId, '===');
|
|
|
|
// Clean up blob URLs when navigating away from images or search pages
|
|
if (typeof cleanupBlobCache === 'function' &&
|
|
(app.currentPage === 'images' || app.currentPage === 'search')) {
|
|
cleanupBlobCache();
|
|
}
|
|
|
|
// Hide all pages
|
|
const pages = document.querySelectorAll('.page');
|
|
console.log('Found pages:', pages.length);
|
|
pages.forEach((page, index) => {
|
|
console.log(`Page ${index}: ${page.id}, currently visible: ${page.style.display !== 'none'}`);
|
|
page.style.display = 'none';
|
|
});
|
|
|
|
// Show the selected page
|
|
const targetPageId = pageId + 'Page';
|
|
const targetPage = document.getElementById(targetPageId);
|
|
console.log('Looking for page with ID:', targetPageId);
|
|
console.log('Target page element:', targetPage);
|
|
|
|
if (targetPage) {
|
|
console.log('Setting target page display to block');
|
|
targetPage.style.display = 'block';
|
|
console.log('Target page is now visible:', targetPage.style.display === 'block');
|
|
|
|
// Update URL hash only if it's different to avoid loops
|
|
const currentHash = window.location.hash.substring(1);
|
|
if (currentHash !== pageId) {
|
|
console.log('Updating URL hash from', currentHash, 'to:', pageId);
|
|
window.location.hash = pageId;
|
|
} else {
|
|
console.log('Hash already correct, not updating');
|
|
}
|
|
|
|
// Update navigation active state
|
|
updateNavActiveState(pageId);
|
|
|
|
// Update app state
|
|
if (window.SeReactApp) {
|
|
window.SeReactApp.currentPage = pageId;
|
|
}
|
|
app.currentPage = pageId; // Also update the local app state
|
|
|
|
// Load page data if needed
|
|
console.log('About to load page data for:', pageId);
|
|
loadPageData(pageId);
|
|
console.log('=== showPage completed for:', pageId, '===');
|
|
} else {
|
|
console.error('Target page not found:', targetPageId);
|
|
console.log('Available page IDs:', Array.from(document.querySelectorAll('.page')).map(p => p.id));
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in showPage:', error);
|
|
showAlert('Error loading page: ' + error.message, 'danger');
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
console.log('=== loadPageData called with pageId:', pageId, '===');
|
|
try {
|
|
switch (pageId) {
|
|
case 'config':
|
|
console.log('Loading config page - about to call initializeConfigForm');
|
|
// Add a small delay to ensure the page is visible before initializing the form
|
|
setTimeout(() => {
|
|
console.log('Timeout fired, calling initializeConfigForm now');
|
|
initializeConfigForm();
|
|
}, 100);
|
|
break;
|
|
case 'images':
|
|
console.log('Loading images page');
|
|
loadImages();
|
|
break;
|
|
case 'teams':
|
|
console.log('Loading teams page');
|
|
loadTeams();
|
|
break;
|
|
case 'users':
|
|
console.log('Loading users page');
|
|
loadUsers();
|
|
break;
|
|
case 'apiKeys':
|
|
console.log('Loading apiKeys page');
|
|
loadApiKeys();
|
|
break;
|
|
case 'search':
|
|
console.log('Loading search page');
|
|
initializeSearchForm();
|
|
break;
|
|
default:
|
|
console.log('No specific loader for page:', pageId);
|
|
}
|
|
console.log('=== loadPageData completed for:', pageId, '===');
|
|
} catch (error) {
|
|
console.error('Error in loadPageData:', error);
|
|
}
|
|
}
|
|
|
|
// Alert system
|
|
function showAlert(message, type = 'info', persistent = false) {
|
|
const alertContainer = document.getElementById('alertContainer');
|
|
|
|
const alertId = 'alert-' + Date.now();
|
|
const alertHtml = `
|
|
<div id="${alertId}" class="alert alert-${type} alert-dismissible fade show" role="alert">
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
`;
|
|
|
|
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 = `
|
|
<div class="modal fade" id="${id}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">${title}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
${body}
|
|
</div>
|
|
${footer ? `<div class="modal-footer">${footer}</div>` : ''}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
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 = '<span class="loading-spinner"></span> 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);
|
|
});
|
|
}
|
|
|
|
// Initialize UI components (called from app.js)
|
|
function initializeUI() {
|
|
console.log('UI initialization called from app.js');
|
|
|
|
// Initialize tooltips and popovers
|
|
initializeTooltips();
|
|
initializePopovers();
|
|
|
|
// Update navigation state
|
|
updateNavigationState();
|
|
|
|
// Show initial page
|
|
const hash = window.location.hash.substring(1);
|
|
const initialPage = hash || 'home';
|
|
console.log('Initial page:', initialPage);
|
|
|
|
// Set initial app state
|
|
if (window.SeReactApp) {
|
|
window.SeReactApp.currentPage = initialPage;
|
|
}
|
|
|
|
showPage(initialPage);
|
|
}
|
|
|
|
// Test function for debugging
|
|
function testPageNavigation() {
|
|
console.log('Testing page navigation...');
|
|
console.log('Available pages:', document.querySelectorAll('.page').length);
|
|
|
|
const pages = ['home', 'config', 'teams', 'users'];
|
|
pages.forEach(pageId => {
|
|
const pageElement = document.getElementById(pageId + 'Page');
|
|
console.log(`Page ${pageId}:`, pageElement ? 'Found' : 'NOT FOUND');
|
|
});
|
|
|
|
// Test showing teams page
|
|
console.log('Testing showPage("teams")...');
|
|
showPage('teams');
|
|
}
|
|
|
|
// Make test function available globally
|
|
window.testPageNavigation = testPageNavigation;
|