2025-08-16 00:04:05 -06:00

221 lines
8.0 KiB
JavaScript

// Main application entry point
import { CONFIG, loadDomainConfig } from './config.js';
import { hideLoading, showStatus, setViewportDimensions } from './utils.js';
import { checkAuth } from './auth.js';
import { initializeMap, getMap } from './map-manager.js';
import { loadLocations } from './location-manager.js';
import { setupEventListeners } from './ui-controls.js';
import { UnifiedSearchManager } from './search-manager.js';
import { cutManager } from './cut-manager.js';
import { initializeCutControls } from './cut-controls.js';
// Application state
let refreshInterval = null;
let unifiedSearchManager = null;
// Initialize the application
document.addEventListener('DOMContentLoaded', async () => {
// Set initial viewport dimensions and listen for resize events
setViewportDimensions();
window.addEventListener('resize', setViewportDimensions);
window.addEventListener('orientationchange', () => {
// Add a small delay for orientation change to complete
setTimeout(setViewportDimensions, 100);
});
console.log('DOM loaded, initializing application...');
try {
// Load domain configuration first
await loadDomainConfig();
// First check authentication
await checkAuth();
// Setup temp user security measures after authentication
setupTempUserSecurity();
// Then initialize the map
await initializeMap();
// Initialize cut manager after map is ready
await cutManager.initialize(getMap());
// Initialize cut controls for public map
await initializeCutControls();
// Only load locations after map is ready
await loadLocations();
// Setup other features
setupEventListeners();
setupAutoRefresh();
// Initialize Unified Search
await initializeUnifiedSearch();
} catch (error) {
console.error('Initialization error:', error);
showStatus('Failed to initialize application', 'error');
} finally {
hideLoading();
}
});
function setupAutoRefresh() {
// Import currentUser to check user type
import('./auth.js').then(authModule => {
const { currentUser } = authModule;
// Use longer interval for temp users to avoid rate limiting
const refreshInterval_ms = currentUser?.userType === 'temp' ?
120000 : // 2 minutes for temp users
60000; // 1 minute for regular users (increased from 30 seconds)
let consecutiveErrors = 0;
const maxErrors = 3;
refreshInterval = setInterval(async () => {
try {
await loadLocations();
consecutiveErrors = 0; // Reset error count on success
} catch (error) {
consecutiveErrors++;
console.warn(`Location refresh failed (${consecutiveErrors}/${maxErrors}):`, error);
// If we've had too many consecutive errors, slow down the refresh
if (consecutiveErrors >= maxErrors) {
console.log('Too many consecutive errors, slowing down refresh interval');
clearInterval(refreshInterval);
// Restart with a longer interval
const slowInterval = refreshInterval_ms * 2; // Double the interval
refreshInterval = setInterval(async () => {
try {
await loadLocations();
consecutiveErrors = 0;
} catch (error) {
console.warn('Location refresh failed:', error);
}
}, slowInterval);
}
}
}, refreshInterval_ms);
if (currentUser?.userType === 'temp') {
console.log('Auto-refresh set to 2 minutes for temporary account');
} else {
console.log('Auto-refresh set to 1 minute for regular account');
}
}).catch(error => {
// Fallback to default interval if auth module fails to load
refreshInterval = setInterval(() => {
loadLocations();
}, CONFIG.REFRESH_INTERVAL);
});
}
// Clean up on page unload
window.addEventListener('beforeunload', () => {
if (refreshInterval) {
clearInterval(refreshInterval);
}
});
// Initialize Unified Search
async function initializeUnifiedSearch() {
try {
// Get config from server
const configResponse = await fetch('/api/config');
const config = await configResponse.json();
unifiedSearchManager = new UnifiedSearchManager({
mkdocsUrl: config.mkdocsUrl || 'http://localhost:4002',
minSearchLength: 2
});
const initialized = await unifiedSearchManager.initialize();
if (initialized) {
// Bind to search container
const searchContainer = document.querySelector('.unified-search-container');
if (searchContainer) {
const bound = unifiedSearchManager.bindToElements(searchContainer);
if (bound) {
console.log('Unified search ready');
} else {
console.warn('Failed to bind unified search to elements');
}
} else {
console.warn('Unified search container not found');
}
} else {
console.warn('Unified search could not be initialized');
}
} catch (error) {
console.error('Error setting up unified search:', error);
}
}
// Setup security measures for temp users
function setupTempUserSecurity() {
// Import currentUser from auth module
import('./auth.js').then(authModule => {
const { currentUser } = authModule;
if (currentUser?.userType === 'temp') {
console.log('Applying temp user security measures...');
// Disable right-click context menu
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
return false;
});
// Basic developer tools detection
const devtools = { open: false };
let devtoolsTimer = setInterval(() => {
// Detect if developer tools are open by checking window dimensions
if (window.outerHeight - window.innerHeight > 200 ||
window.outerWidth - window.innerWidth > 200) {
if (!devtools.open) {
console.clear();
console.log('Access to developer tools is restricted for temporary accounts.');
console.log('Please contact an administrator for full access.');
}
devtools.open = true;
} else {
devtools.open = false;
}
}, 1000);
// Clear interval on page unload
window.addEventListener('beforeunload', () => {
if (devtoolsTimer) {
clearInterval(devtoolsTimer);
}
});
// Disable common keyboard shortcuts for developer tools
document.addEventListener('keydown', (e) => {
// F12
if (e.keyCode === 123) {
e.preventDefault();
return false;
}
// Ctrl+Shift+I, Ctrl+Shift+J, Ctrl+U
if (e.ctrlKey && e.shiftKey && (e.keyCode === 73 || e.keyCode === 74)) {
e.preventDefault();
return false;
}
// Ctrl+U (view source)
if (e.ctrlKey && e.keyCode === 85) {
e.preventDefault();
return false;
}
});
}
});
}