232 lines
8.5 KiB
JavaScript
232 lines
8.5 KiB
JavaScript
// Main application entry point
|
|
import { CONFIG, loadDomainConfig } from './config.js';
|
|
import { hideLoading, showStatus, setViewportDimensions, updateLoadingMessage } 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, checking authentication...');
|
|
|
|
try {
|
|
// Load domain configuration first
|
|
updateLoadingMessage('Loading configuration...');
|
|
await loadDomainConfig();
|
|
|
|
// CRITICAL: Check authentication FIRST before any UI initialization
|
|
// This prevents the map from briefly showing before redirect
|
|
updateLoadingMessage('Authenticating...');
|
|
await checkAuth();
|
|
|
|
console.log('Authentication confirmed, initializing application...');
|
|
|
|
// Setup temp user security measures immediately after authentication
|
|
await setupUserSecurity();
|
|
|
|
// Then initialize the map
|
|
updateLoadingMessage('Initializing map...');
|
|
await initializeMap();
|
|
|
|
// Initialize cut manager after map is ready
|
|
updateLoadingMessage('Loading map overlays...');
|
|
await cutManager.initialize(getMap());
|
|
|
|
// Initialize cut controls for public map
|
|
await initializeCutControls();
|
|
|
|
// Only load locations after map is ready
|
|
updateLoadingMessage('Loading locations...');
|
|
await loadLocations();
|
|
|
|
// Setup other features
|
|
setupEventListeners();
|
|
setupAutoRefresh();
|
|
|
|
// Initialize Unified Search
|
|
updateLoadingMessage('Setting up search...');
|
|
await initializeUnifiedSearch();
|
|
|
|
} catch (error) {
|
|
console.error('Initialization error:', error);
|
|
// If authentication fails, we should already be redirected
|
|
// But in case of other errors, clean up the loading state
|
|
if (!error.message.includes('Not authenticated') && !error.message.includes('Account expired')) {
|
|
document.body.classList.remove('authenticating');
|
|
document.body.classList.add('authenticated');
|
|
document.getElementById('app').classList.remove('app-hidden');
|
|
showStatus('Failed to initialize application', 'error');
|
|
}
|
|
} finally {
|
|
// Only hide loading if we're not being redirected for authentication
|
|
if (!document.body.classList.contains('authenticating')) {
|
|
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 non-admin users
|
|
async function setupUserSecurity() {
|
|
// Import currentUser from auth module
|
|
const { currentUser } = await import('./auth.js');
|
|
|
|
if (currentUser?.userType !== 'admin') {
|
|
// Override console methods for all non-admin users
|
|
const noop = () => {};
|
|
console.log = noop;
|
|
console.debug = noop;
|
|
console.info = noop;
|
|
console.warn = noop;
|
|
console.error = noop;
|
|
console.trace = noop;
|
|
console.dir = noop;
|
|
console.dirxml = noop;
|
|
console.group = noop;
|
|
console.groupEnd = noop;
|
|
console.time = noop;
|
|
console.timeEnd = noop;
|
|
console.assert = noop;
|
|
console.profile = noop;
|
|
}
|
|
|
|
// Additional temp user specific restrictions
|
|
if (currentUser?.userType === 'temp') {
|
|
// Disable right-click context menu
|
|
document.addEventListener('contextmenu', (e) => {
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
// 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;
|
|
}
|
|
});
|
|
}
|
|
}
|