1252 lines
52 KiB
JavaScript
1252 lines
52 KiB
JavaScript
/**
|
|
* Main Menu System
|
|
* Handles the main menu UI, save management, and game initialization
|
|
*/
|
|
|
|
console.log('[MAIN MENU] MainMenu.js script loaded');
|
|
|
|
class MainMenu {
|
|
constructor() {
|
|
console.log('[MAIN MENU] Constructor called');
|
|
this.mainMenu = document.getElementById('mainMenu');
|
|
this.selectedSlot = null;
|
|
this.saveSlotsCount = 3; // Number of save slots
|
|
|
|
console.log('[MAIN MENU] Initializing elements');
|
|
this.initializeElements();
|
|
|
|
console.log('[MAIN MENU] Initializing event listeners');
|
|
this.bindEvents();
|
|
|
|
// Delay save folder verification until electronAPI is available
|
|
this.initializeAfterElectronAPI();
|
|
}
|
|
|
|
initializeAfterElectronAPI() {
|
|
// Check if electronAPI is available, if not wait for it
|
|
if (window.electronAPI) {
|
|
console.log('[MAIN MENU] electronAPI available, proceeding with initialization');
|
|
this.completeInitialization();
|
|
} else {
|
|
console.log('[MAIN MENU] electronAPI not available, waiting...');
|
|
// Wait for electronAPI to be available
|
|
setTimeout(() => {
|
|
this.initializeAfterElectronAPI();
|
|
}, 100);
|
|
}
|
|
}
|
|
|
|
async completeInitialization() {
|
|
console.log('[MAIN MENU] Starting save folder verification');
|
|
this.verifySaveFolders();
|
|
|
|
console.log('[MAIN MENU] Loading save data');
|
|
await this.loadSaveData();
|
|
|
|
console.log('[MAIN MENU] Updating save slots');
|
|
this.updateSaveSlots();
|
|
|
|
console.log('[MAIN MENU] Constructor completed');
|
|
}
|
|
|
|
verifySaveFolders() {
|
|
console.log('[MAIN MENU] Verifying save folders...');
|
|
console.log('[MAIN MENU] window.electronAPI available:', !!window.electronAPI);
|
|
|
|
try {
|
|
// Use Electron's IPC instead of direct Node.js access
|
|
if (window.electronAPI) {
|
|
console.log('[MAIN MENU] Using Electron API for folder operations');
|
|
console.log('[MAIN MENU] createSaveFolders method available:', typeof window.electronAPI.createSaveFolders);
|
|
|
|
// Request folder creation through main process
|
|
window.electronAPI.createSaveFolders(this.saveSlotsCount).then((result) => {
|
|
console.log('[MAIN MENU] createSaveFolders response:', result);
|
|
if (result.success) {
|
|
console.log('[MAIN MENU] Save folders created successfully:', result.paths);
|
|
this.savePaths = result.paths;
|
|
} else {
|
|
console.error('[MAIN MENU] Failed to create save folders:', result.error);
|
|
console.log('[MAIN MENU] Falling back to localStorage save system');
|
|
this.useLocalStorageFallback();
|
|
}
|
|
}).catch((error) => {
|
|
console.error('[MAIN MENU] IPC error:', error);
|
|
console.log('[MAIN MENU] Falling back to localStorage save system');
|
|
this.useLocalStorageFallback();
|
|
});
|
|
|
|
} else {
|
|
console.log('[MAIN MENU] Electron API not available, using localStorage fallback');
|
|
this.useLocalStorageFallback();
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[MAIN MENU] Error verifying save folders:', error);
|
|
console.log('[MAIN MENU] Falling back to localStorage save system');
|
|
this.useLocalStorageFallback();
|
|
}
|
|
}
|
|
|
|
hideLoadingScreenAndShowGame() {
|
|
console.log('[MAIN MENU] Hiding loading screen and showing game interface');
|
|
|
|
// Hide loading screen
|
|
const loadingScreen = document.getElementById('loadingScreen');
|
|
if (loadingScreen) {
|
|
loadingScreen.classList.add('hidden');
|
|
console.log('[MAIN MENU] Loading screen hidden');
|
|
}
|
|
|
|
// Show game interface
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
if (gameInterface) {
|
|
gameInterface.classList.remove('hidden');
|
|
console.log('[MAIN MENU] Game interface shown');
|
|
}
|
|
|
|
// Show game container
|
|
const gameContainer = document.getElementById('gameContainer');
|
|
if (gameContainer) {
|
|
gameContainer.classList.remove('hidden');
|
|
console.log('[MAIN MENU] Game container shown');
|
|
}
|
|
}
|
|
|
|
useLocalStorageFallback() {
|
|
// Fallback for browser testing or when Electron API fails
|
|
for (let i = 1; i <= this.saveSlotsCount; i++) {
|
|
const saveKey = `gso_save_slot_${i}`;
|
|
if (!localStorage.getItem(saveKey)) {
|
|
const saveInfo = {
|
|
slot: i,
|
|
created: new Date().toISOString(),
|
|
version: '1.0.0',
|
|
exists: false
|
|
};
|
|
localStorage.setItem(saveKey, JSON.stringify(saveInfo));
|
|
console.log(`[MAIN MENU] Created localStorage save info for slot ${i}`);
|
|
}
|
|
}
|
|
|
|
// Mark that we're using localStorage
|
|
this.savePaths = null;
|
|
console.log('[MAIN MENU] Using localStorage save system');
|
|
}
|
|
|
|
initializeElements() {
|
|
// Menu sections
|
|
this.mainMenu = document.getElementById('mainMenu');
|
|
this.loginSection = document.getElementById('loginSection');
|
|
this.saveSection = document.getElementById('saveSection');
|
|
this.optionsSection = document.getElementById('optionsSection');
|
|
|
|
// Login buttons
|
|
this.ssoLoginBtn = document.getElementById('ssoLoginBtn');
|
|
this.offlineBtn = document.getElementById('offlineBtn');
|
|
|
|
// Save selection
|
|
this.saveSlots = document.querySelectorAll('.save-slot');
|
|
this.backToLoginBtn = document.getElementById('backToLoginBtn');
|
|
|
|
// Save confirmation section
|
|
this.confirmSection = document.getElementById('confirmSection');
|
|
this.confirmSlotTitle = document.getElementById('confirmSlotTitle');
|
|
this.confirmSaveDetails = document.getElementById('confirmSaveDetails');
|
|
this.confirmLevel = document.getElementById('confirmLevel');
|
|
this.confirmShip = document.getElementById('confirmShip');
|
|
this.confirmPlayTime = document.getElementById('confirmPlayTime');
|
|
this.confirmLastPlayed = document.getElementById('confirmLastPlayed');
|
|
this.confirmNewGameBtn = document.getElementById('confirmNewGameBtn');
|
|
this.confirmContinueBtn = document.getElementById('confirmContinueBtn');
|
|
this.confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
|
|
console.log('[MAIN MENU] confirmDeleteBtn found:', !!this.confirmDeleteBtn);
|
|
this.confirmSettingsBtn = document.getElementById('confirmSettingsBtn');
|
|
this.backToSavesFromConfirmBtn = document.getElementById('backToSavesFromConfirmBtn');
|
|
|
|
// Game options
|
|
this.newGameBtn = document.getElementById('newGameBtn');
|
|
this.continueBtn = document.getElementById('continueBtn');
|
|
this.deleteSaveBtn = document.getElementById('deleteSaveBtn');
|
|
console.log('[MAIN MENU] deleteSaveBtn found:', !!this.deleteSaveBtn);
|
|
this.settingsBtn = document.getElementById('settingsBtn');
|
|
this.quitBtn = document.getElementById('quitBtn');
|
|
this.backToSavesBtn = document.getElementById('backToSavesBtn');
|
|
|
|
// Footer links
|
|
this.aboutBtn = document.getElementById('aboutBtn');
|
|
this.helpBtn = document.getElementById('helpBtn');
|
|
}
|
|
|
|
bindEvents() {
|
|
// Login events
|
|
this.ssoLoginBtn?.addEventListener('click', () => this.handleSSOLogin());
|
|
this.offlineBtn?.addEventListener('click', () => this.handleOfflineLogin());
|
|
|
|
// Save selection events
|
|
this.saveSlots.forEach(slot => {
|
|
slot.addEventListener('click', () => this.selectSaveSlot(slot));
|
|
});
|
|
|
|
this.backToLoginBtn?.addEventListener('click', () => this.showLoginSection());
|
|
|
|
// Save confirmation events
|
|
this.confirmNewGameBtn?.addEventListener('click', () => this.startNewGame());
|
|
this.confirmContinueBtn?.addEventListener('click', () => this.continueGame());
|
|
this.confirmDeleteBtn?.addEventListener('click', () => {
|
|
console.log('[MAIN MENU] Delete button clicked');
|
|
this.deleteSave();
|
|
});
|
|
this.confirmSettingsBtn?.addEventListener('click', () => this.showSettings());
|
|
this.backToSavesFromConfirmBtn?.addEventListener('click', () => this.showSaveSection());
|
|
|
|
// Game options events
|
|
this.newGameBtn?.addEventListener('click', () => this.startNewGame());
|
|
this.continueBtn?.addEventListener('click', () => this.continueGame());
|
|
this.deleteSaveBtn?.addEventListener('click', () => {
|
|
console.log('[MAIN MENU] Delete save button clicked');
|
|
this.deleteSave();
|
|
});
|
|
this.settingsBtn?.addEventListener('click', () => this.showSettings());
|
|
this.quitBtn?.addEventListener('click', () => this.quitGame());
|
|
this.backToSavesBtn?.addEventListener('click', async () => this.showSaveSection());
|
|
|
|
// Footer events
|
|
this.aboutBtn?.addEventListener('click', () => this.showAbout());
|
|
this.helpBtn?.addEventListener('click', () => this.showHelp());
|
|
}
|
|
|
|
showSection(sectionName) {
|
|
// Hide all sections
|
|
this.loginSection?.classList.add('hidden');
|
|
this.saveSection?.classList.add('hidden');
|
|
this.confirmSection?.classList.add('hidden');
|
|
this.optionsSection?.classList.add('hidden');
|
|
|
|
// Show selected section
|
|
const section = document.getElementById(`${sectionName}Section`);
|
|
if (section) {
|
|
section.classList.remove('hidden');
|
|
this.currentSection = sectionName;
|
|
}
|
|
}
|
|
|
|
showLoginSection() {
|
|
this.showSection('login');
|
|
}
|
|
|
|
async showSaveSection() {
|
|
this.showSection('save');
|
|
await this.loadSaveData();
|
|
this.updateSaveSlots();
|
|
}
|
|
|
|
showConfirmSection() {
|
|
this.showSection('confirm');
|
|
// Clear any previous data to prevent contamination
|
|
this.clearConfirmSectionData();
|
|
this.updateConfirmSection();
|
|
}
|
|
|
|
updateConfirmSection() {
|
|
const hasSave = this.selectedSlot && this.saveData[this.selectedSlot];
|
|
|
|
// Update slot title
|
|
this.confirmSlotTitle.textContent = `Slot ${this.selectedSlot}`;
|
|
|
|
if (hasSave) {
|
|
const saveData = this.saveData[this.selectedSlot];
|
|
const player = saveData.player || {};
|
|
|
|
// Update save details
|
|
const playerLevel = player.stats?.level || player.level || 1;
|
|
|
|
// Get ship name from multiple possible fields
|
|
const shipName = player.shipName || player.ship?.name || player.currentShip || player.selectedShip || saveData.shipName || saveData.currentShip || 'Unknown Ship';
|
|
|
|
// Calculate play time - check multiple possible fields and format properly
|
|
const playTime = player.playTime || player.stats?.playTime || saveData.playTime || saveData.totalPlayTime || 0;
|
|
|
|
// Handle different time formats (seconds, milliseconds, or already formatted)
|
|
let totalSeconds = 0;
|
|
if (typeof playTime === 'number') {
|
|
// If it's a large number, it might be milliseconds
|
|
if (playTime > 3600) {
|
|
totalSeconds = Math.floor(playTime / 1000);
|
|
} else {
|
|
totalSeconds = Math.floor(playTime);
|
|
}
|
|
} else if (typeof playTime === 'string') {
|
|
// If it's already formatted, use it as-is
|
|
const playTimeText = playTime;
|
|
} else {
|
|
totalSeconds = 0;
|
|
}
|
|
|
|
// Format time as dd.hh.nn.ss
|
|
const days = Math.floor(totalSeconds / 86400);
|
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
let playTimeText = '';
|
|
if (days > 0) {
|
|
playTimeText = `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (hours > 0) {
|
|
playTimeText = `${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (minutes > 0) {
|
|
playTimeText = `${minutes}m ${seconds}s`;
|
|
} else {
|
|
playTimeText = `${seconds}s`;
|
|
}
|
|
|
|
// Last played - check multiple possible date fields
|
|
const lastPlayed = saveData.lastPlayed || saveData.lastSave || saveData.timestamp || saveData.date || new Date();
|
|
const formattedDate = lastPlayed instanceof Date ? lastPlayed.toLocaleDateString() :
|
|
(typeof lastPlayed === 'string' ? lastPlayed : new Date(lastPlayed).toLocaleDateString());
|
|
const lastPlayedText = formattedDate === new Date().toLocaleDateString() ? 'Today' : formattedDate;
|
|
|
|
// Restore textContent properties
|
|
this.confirmLevel.textContent = playerLevel;
|
|
this.confirmShip.textContent = shipName;
|
|
this.confirmPlayTime.textContent = playTimeText;
|
|
this.confirmLastPlayed.textContent = lastPlayedText;
|
|
|
|
// Format save info with consistent alignment and labels
|
|
const saveInfoText = `Level: ${playerLevel}\n\nShip: ${shipName}\n\nPlay Time: ${playTimeText}\n\nLast Played: ${lastPlayedText}`;
|
|
|
|
// Update save details with pre-formatted text for alignment
|
|
this.confirmSaveDetails.innerHTML = `<pre style="margin: 0; font-family: 'Space Mono', monospace; color: white; font-size: 0.9em; line-height: 1.6;">${saveInfoText}</pre>`;
|
|
|
|
// Has save data - always show Continue, hide New Game
|
|
this.confirmContinueBtn.style.display = 'block';
|
|
this.confirmContinueBtn.disabled = false;
|
|
this.confirmDeleteBtn.style.display = 'block';
|
|
this.confirmDeleteBtn.disabled = false;
|
|
this.confirmSettingsBtn.style.display = 'block';
|
|
this.confirmSettingsBtn.disabled = false;
|
|
this.confirmNewGameBtn.style.display = 'none';
|
|
this.confirmNewGameBtn.disabled = true;
|
|
} else {
|
|
// No save data - show new game option
|
|
this.confirmLevel.textContent = 'New';
|
|
this.confirmShip.textContent = 'New Adventure';
|
|
this.confirmPlayTime.textContent = '0h 0m';
|
|
this.confirmLastPlayed.textContent = 'Never';
|
|
|
|
// Show new game and settings buttons, hide continue and delete
|
|
this.confirmNewGameBtn.style.display = 'block';
|
|
this.confirmNewGameBtn.disabled = false;
|
|
this.confirmSettingsBtn.style.display = 'block';
|
|
this.confirmSettingsBtn.disabled = false;
|
|
this.confirmContinueBtn.style.display = 'none';
|
|
this.confirmDeleteBtn.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
showOptionsSection() {
|
|
this.showSection('options');
|
|
// Clear any previous data to prevent contamination
|
|
this.clearOptionsSectionData();
|
|
this.updateGameOptions();
|
|
}
|
|
|
|
clearConfirmSectionData() {
|
|
// Clear individual text content elements
|
|
if (this.confirmLevel) this.confirmLevel.textContent = '';
|
|
if (this.confirmShip) this.confirmShip.textContent = '';
|
|
if (this.confirmPlayTime) this.confirmPlayTime.textContent = '';
|
|
if (this.confirmLastPlayed) this.confirmLastPlayed.textContent = '';
|
|
|
|
// Clear the save details display
|
|
if (this.confirmSaveDetails) {
|
|
this.confirmSaveDetails.innerHTML = '';
|
|
}
|
|
}
|
|
|
|
clearOptionsSectionData() {
|
|
// Clear the save info details display
|
|
const saveInfoDetails = document.getElementById('saveInfoDetails');
|
|
if (saveInfoDetails) {
|
|
saveInfoDetails.innerHTML = '';
|
|
}
|
|
}
|
|
|
|
handleSSOLogin() {
|
|
// Placeholder for SSO login
|
|
console.log('[MAIN MENU] SSO login requested (placeholder)');
|
|
|
|
// Show loading state
|
|
this.ssoLoginBtn.disabled = true;
|
|
this.ssoLoginBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Connecting...';
|
|
|
|
// Simulate SSO login (will be implemented later)
|
|
setTimeout(() => {
|
|
this.isLoggedIn = true;
|
|
this.ssoLoginBtn.innerHTML = '<i class="fas fa-check"></i> Logged In';
|
|
this.ssoLoginBtn.disabled = false;
|
|
|
|
// Show save selection
|
|
this.showSaveSection();
|
|
}, 1500);
|
|
}
|
|
|
|
handleOfflineLogin() {
|
|
console.log('[MAIN MENU] Login successful');
|
|
this.isLoggedIn = true;
|
|
|
|
// Show save selection
|
|
setTimeout(async () => {
|
|
await this.showSaveSection();
|
|
}, 1500);
|
|
}
|
|
|
|
async loadSaveData() {
|
|
// Initialize saveData object
|
|
this.saveData = {};
|
|
|
|
console.log('[MAIN MENU] Loading save data from file system');
|
|
|
|
// Check if we have save paths and should use file system
|
|
if (this.savePaths && window.electronAPI) {
|
|
console.log('[MAIN MENU] Using file system for save data');
|
|
|
|
// Load save data from file system using the load-game API
|
|
for (let i = 1; i <= 3; i++) {
|
|
try {
|
|
console.log(`[MAIN MENU] Loading save file for slot ${i}`);
|
|
|
|
const result = await window.electronAPI.loadGame(i);
|
|
|
|
if (result.success && result.data) {
|
|
this.saveData[i] = result.data;
|
|
console.log(`[MAIN MENU] Slot ${i} loaded successfully:`, this.saveData[i]);
|
|
} else {
|
|
console.log(`[MAIN MENU] Slot ${i} has no save file or failed to load:`, result.error);
|
|
this.saveData[i] = null;
|
|
}
|
|
} catch (error) {
|
|
console.error(`[MAIN MENU] Error reading save slot ${i}:`, error);
|
|
this.saveData[i] = null;
|
|
}
|
|
}
|
|
} else {
|
|
console.log('[MAIN MENU] Using localStorage fallback for save data');
|
|
console.log('[MAIN MENU] Available localStorage keys:', Object.keys(localStorage));
|
|
|
|
// Fallback to localStorage
|
|
for (let i = 1; i <= 3; i++) {
|
|
const saveKey = `gso_save_slot_${i}`;
|
|
const saveData = localStorage.getItem(saveKey);
|
|
|
|
console.log(`[MAIN MENU] Slot ${i} key: ${saveKey}, data:`, saveData);
|
|
|
|
if (saveData) {
|
|
try {
|
|
this.saveData[i] = JSON.parse(saveData);
|
|
console.log(`[MAIN MENU] Slot ${i} parsed successfully:`, this.saveData[i]);
|
|
} catch (error) {
|
|
console.error(`[MAIN MENU] Error loading save slot ${i}:`, error);
|
|
this.saveData[i] = null;
|
|
}
|
|
} else {
|
|
console.log(`[MAIN MENU] Slot ${i} has no data`);
|
|
this.saveData[i] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('[MAIN MENU] Final saveData object:', this.saveData);
|
|
}
|
|
|
|
updateSaveSlots() {
|
|
console.log('[MAIN MENU] Updating save slots UI');
|
|
console.log('[MAIN MENU] this.saveSlots:', this.saveSlots);
|
|
console.log('[MAIN MENU] this.saveData:', this.saveData);
|
|
|
|
// Check if saveSlots elements exist
|
|
if (!this.saveSlots || this.saveSlots.length === 0) {
|
|
console.log('[MAIN MENU] Save slots not found, re-initializing elements');
|
|
this.saveSlots = document.querySelectorAll('.save-slot');
|
|
console.log('[MAIN MENU] Re-initialized saveSlots:', this.saveSlots);
|
|
}
|
|
|
|
if (!this.saveSlots || this.saveSlots.length === 0) {
|
|
console.error('[MAIN MENU] Could not find save slot elements in DOM');
|
|
return;
|
|
}
|
|
|
|
this.saveSlots.forEach((slot, index) => {
|
|
const slotNumber = index + 1;
|
|
const saveInfo = this.saveData[slotNumber];
|
|
|
|
console.log(`[MAIN MENU] Processing slot ${slotNumber}, saveInfo:`, saveInfo);
|
|
|
|
const slotStatus = slot.querySelector('.slot-status');
|
|
const slotName = slot.querySelector('.slot-name');
|
|
const slotDetails = slot.querySelector('.slot-details');
|
|
const slotBtn = slot.querySelector('.slot-btn');
|
|
|
|
console.log(`[MAIN MENU] Found elements for slot ${slotNumber}:`, {
|
|
slotStatus: !!slotStatus,
|
|
slotName: !!slotName,
|
|
slotDetails: !!slotDetails,
|
|
slotBtn: !!slotBtn
|
|
});
|
|
|
|
// Check if this is a valid save game (has actual game data)
|
|
console.log(`[MAIN MENU] Validating save data for slot ${slotNumber}:`, {
|
|
saveInfo: saveInfo,
|
|
hasSaveInfo: !!saveInfo,
|
|
hasPlayer: !!(saveInfo && saveInfo.player),
|
|
hasPlayerStats: !!(saveInfo && saveInfo.player && saveInfo.player.stats),
|
|
playerLevel: saveInfo && saveInfo.player && saveInfo.player.stats ? saveInfo.player.stats.level : 'no player.stats',
|
|
playerKeys: saveInfo && saveInfo.player ? Object.keys(saveInfo.player) : 'no player'
|
|
});
|
|
|
|
const hasValidSave = saveInfo && saveInfo.player && saveInfo.player.stats && saveInfo.player.stats.level !== undefined;
|
|
|
|
if (hasValidSave) {
|
|
// Update with existing save data
|
|
console.log(`[MAIN MENU] Slot ${slotNumber} has valid save data - showing Load`);
|
|
if (slotStatus) {
|
|
slotStatus.textContent = 'Level ' + (saveInfo.player.stats.level || 1);
|
|
slotStatus.className = 'slot-status has-data';
|
|
}
|
|
if (slotName) {
|
|
slotName.textContent = saveInfo.player.info.name || 'Commander';
|
|
}
|
|
|
|
// Format playtime and last played
|
|
const playTime = saveInfo.player.stats.playTime || saveInfo.player.playTime || 0;
|
|
|
|
// Handle different time formats (seconds, milliseconds, or already formatted)
|
|
let totalSeconds = 0;
|
|
if (typeof playTime === 'number') {
|
|
// If it's a large number, it might be milliseconds
|
|
if (playTime > 3600) {
|
|
totalSeconds = Math.floor(playTime / 1000);
|
|
} else {
|
|
totalSeconds = Math.floor(playTime);
|
|
}
|
|
} else if (typeof playTime === 'string') {
|
|
// If it's already formatted, use it as-is
|
|
var playtime = playTime;
|
|
} else {
|
|
totalSeconds = 0;
|
|
}
|
|
|
|
// Only format if we haven't already set playtime from a string
|
|
if (typeof playtime !== 'string') {
|
|
// Format time as dd.hh.nn.ss
|
|
const days = Math.floor(totalSeconds / 86400);
|
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
if (days > 0) {
|
|
playtime = `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (hours > 0) {
|
|
playtime = `${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (minutes > 0) {
|
|
playtime = `${minutes}m ${seconds}s`;
|
|
} else {
|
|
playtime = `${seconds}s`;
|
|
}
|
|
}
|
|
|
|
const lastSaved = saveInfo.lastSave ? new Date(saveInfo.lastSave).toLocaleDateString() : 'Unknown';
|
|
if (slotDetails) {
|
|
slotDetails.textContent = `Playtime: ${playtime} | Saved: ${lastSaved}`;
|
|
}
|
|
|
|
if (slotBtn) {
|
|
slotBtn.textContent = 'Select';
|
|
slotBtn.onclick = () => this.selectSaveSlot(slot);
|
|
}
|
|
} else {
|
|
// Empty slot or invalid/placeholder save
|
|
console.log(`[MAIN MENU] Slot ${slotNumber} is empty or invalid - showing New Game`);
|
|
if (slotStatus) {
|
|
slotStatus.textContent = 'Empty';
|
|
slotStatus.className = 'slot-status empty';
|
|
}
|
|
if (slotName) {
|
|
slotName.textContent = 'New Game';
|
|
}
|
|
if (slotDetails) {
|
|
slotDetails.textContent = 'Start a new adventure';
|
|
}
|
|
if (slotBtn) {
|
|
slotBtn.textContent = 'Select';
|
|
slotBtn.onclick = () => this.selectSaveSlot(slot);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
selectSaveSlot(slot) {
|
|
const slotNumber = parseInt(slot.dataset.slot);
|
|
this.selectedSlot = slotNumber;
|
|
|
|
console.log(`[MAIN MENU] Save slot ${slotNumber} selected`);
|
|
|
|
// Show confirmation section
|
|
this.showConfirmSection();
|
|
}
|
|
|
|
updateGameOptions() {
|
|
const hasSave = this.selectedSlot && this.saveData[this.selectedSlot];
|
|
|
|
// Update button states based on save data
|
|
if (hasSave) {
|
|
// Has save data - always show Continue, hide New Game
|
|
this.continueBtn.style.display = 'block';
|
|
this.continueBtn.disabled = false;
|
|
this.continueBtn.innerHTML = '<i class="fas fa-gamepad"></i> Continue';
|
|
|
|
this.newGameBtn.style.display = 'none';
|
|
|
|
this.deleteSaveBtn.style.display = 'block';
|
|
this.deleteSaveBtn.disabled = false;
|
|
this.deleteSaveBtn.innerHTML = '<i class="fas fa-trash"></i> Delete Save';
|
|
|
|
// Update center information display
|
|
this.updateSaveInfoDisplay();
|
|
} else {
|
|
// Show new game button, hide continue button
|
|
this.newGameBtn.style.display = 'block';
|
|
this.newGameBtn.disabled = false;
|
|
this.newGameBtn.innerHTML = '<i class="fas fa-play"></i> Start New Game';
|
|
|
|
this.continueBtn.style.display = 'none';
|
|
|
|
this.deleteSaveBtn.style.display = 'none';
|
|
|
|
// Update center information display for empty slot
|
|
this.updateSaveInfoDisplay();
|
|
}
|
|
}
|
|
|
|
updateSaveInfoDisplay() {
|
|
const saveInfoDetails = document.getElementById('saveInfoDetails');
|
|
if (!saveInfoDetails) return;
|
|
|
|
const hasSave = this.selectedSlot && this.saveData[this.selectedSlot];
|
|
|
|
if (hasSave) {
|
|
const saveData = this.saveData[this.selectedSlot];
|
|
const player = saveData.player || {};
|
|
|
|
// Format save information
|
|
const level = player.stats?.level || player.level || 1;
|
|
const name = player.info ? player.info.name : 'Commander';
|
|
const ship = player.shipName || 'Unknown Ship';
|
|
|
|
// Calculate play time - check multiple possible fields and format properly
|
|
const playTime = player.playTime || player.stats?.playTime || saveData.playTime || saveData.totalPlayTime || 0;
|
|
|
|
// Handle different time formats (seconds, milliseconds, or already formatted)
|
|
let totalSeconds = 0;
|
|
if (typeof playTime === 'number') {
|
|
// If it's a large number, it might be milliseconds
|
|
if (playTime > 3600) {
|
|
totalSeconds = Math.floor(playTime / 1000);
|
|
} else {
|
|
totalSeconds = Math.floor(playTime);
|
|
}
|
|
} else if (typeof playTime === 'string') {
|
|
// If it's already formatted, use it as-is
|
|
var playtime = playTime;
|
|
} else {
|
|
totalSeconds = 0;
|
|
}
|
|
|
|
// Only format if we haven't already set playtime from a string
|
|
if (typeof playtime !== 'string') {
|
|
// Format time as dd.hh.nn.ss
|
|
const days = Math.floor(totalSeconds / 86400);
|
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
|
|
if (days > 0) {
|
|
playtime = `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (hours > 0) {
|
|
playtime = `${hours}h ${minutes}m ${seconds}s`;
|
|
} else if (minutes > 0) {
|
|
playtime = `${minutes}m ${seconds}s`;
|
|
} else {
|
|
playtime = `${seconds}s`;
|
|
}
|
|
}
|
|
|
|
// Check multiple possible date fields and use current date if none found
|
|
const lastSaved = saveData.lastPlayed || saveData.lastSave || saveData.timestamp || new Date().toLocaleDateString();
|
|
const formattedDate = lastSaved === new Date().toLocaleDateString() ? 'Today' :
|
|
(typeof lastSaved === 'string' ? lastSaved : new Date(lastSaved).toLocaleDateString());
|
|
|
|
// Format save info with consistent alignment and labels
|
|
const saveInfoText = `Level: ${level}\n\nShip: ${ship}\n\nPlay Time: ${playtime}\n\nLast Played: ${formattedDate}`;
|
|
|
|
// Update save details with pre-formatted text for alignment
|
|
saveInfoDetails.innerHTML = `<pre style="margin: 0; font-family: 'Space Mono', monospace; color: white; font-size: 0.9em; line-height: 1.6;">${saveInfoText}</pre>`;
|
|
} else {
|
|
saveInfoDetails.innerHTML = `
|
|
<div class="save-info-content">
|
|
<p><strong>Slot:</strong> ${this.selectedSlot || 'None'}</p>
|
|
<p><strong>Status:</strong> Empty</p>
|
|
<p>Ready for new adventure</p>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
startNewGame() {
|
|
if (!this.selectedSlot) {
|
|
console.error('[MAIN MENU] No save slot selected');
|
|
return;
|
|
}
|
|
|
|
console.log(`[MAIN MENU] Starting new game in slot ${this.selectedSlot}`);
|
|
|
|
// Clear existing save data for this slot
|
|
const saveKey = `gso_save_slot_${this.selectedSlot}`;
|
|
localStorage.removeItem(saveKey);
|
|
this.saveData[this.selectedSlot] = null;
|
|
|
|
// Start the game
|
|
this.launchGame('new');
|
|
}
|
|
|
|
continueGame() {
|
|
if (!this.selectedSlot || !this.saveData[this.selectedSlot]) {
|
|
console.error('[MAIN MENU] No save data to continue');
|
|
return;
|
|
}
|
|
|
|
console.log(`[MAIN MENU] Continuing game from slot ${this.selectedSlot}`);
|
|
this.launchGame('continue');
|
|
}
|
|
|
|
async deleteSave() {
|
|
console.log('[MAIN MENU] deleteSave called');
|
|
|
|
if (!this.selectedSlot || !this.saveData[this.selectedSlot]) {
|
|
console.error('[MAIN MENU] No save data to delete', {
|
|
selectedSlot: this.selectedSlot,
|
|
hasSaveData: !!this.saveData[this.selectedSlot]
|
|
});
|
|
return;
|
|
}
|
|
|
|
const saveData = this.saveData[this.selectedSlot];
|
|
const saveInfo = saveData.player ?
|
|
`Level ${saveData.player.stats?.level || saveData.player.level || 1} ${saveData.player.shipName || saveData.player.ship?.name || 'Player'}` :
|
|
'Unknown save data';
|
|
|
|
const confirmMessage = `Are you sure you want to delete the save from slot ${this.selectedSlot}?\n\n${saveInfo}\n\nThis action cannot be undone!`;
|
|
|
|
console.log('[MAIN MENU] Showing confirmation modal');
|
|
|
|
// Show custom confirmation modal
|
|
this.showConfirm(confirmMessage, () => {
|
|
console.log('[MAIN MENU] User confirmed deletion, executing delete');
|
|
this.executeDeleteSave();
|
|
}, () => {
|
|
console.log('[MAIN MENU] User cancelled deletion');
|
|
});
|
|
}
|
|
|
|
async executeDeleteSave() {
|
|
console.log('[MAIN MENU] executeDeleteSave called', {
|
|
selectedSlot: this.selectedSlot
|
|
});
|
|
|
|
try {
|
|
console.log(`[MAIN MENU] Deleting save data from slot ${this.selectedSlot}`);
|
|
|
|
// Remove from localStorage
|
|
const saveKey = `gso_save_slot_${this.selectedSlot}`;
|
|
console.log(`[MAIN MENU] Removing localStorage key: ${saveKey}`);
|
|
localStorage.removeItem(saveKey);
|
|
|
|
// Verify removal
|
|
const remainingData = localStorage.getItem(saveKey);
|
|
console.log(`[MAIN MENU] Verification - save data still exists: ${!!remainingData}`);
|
|
|
|
// Remove from file system if available
|
|
if (window.electronAPI && window.electronAPI.deleteSaveFile) {
|
|
console.log(`[MAIN MENU] Deleting save file via Electron API`);
|
|
await window.electronAPI.deleteSaveFile(this.selectedSlot);
|
|
console.log(`[MAIN MENU] Save file deleted from slot ${this.selectedSlot} via Electron API`);
|
|
} else if (window.electronAPI && window.electronAPI.deleteSave) {
|
|
console.log(`[MAIN MENU] Deleting save file via Electron API (deleteSave method)`);
|
|
await window.electronAPI.deleteSave(this.selectedSlot);
|
|
console.log(`[MAIN MENU] Save file deleted from slot ${this.selectedSlot} via Electron API`);
|
|
} else {
|
|
console.log(`[MAIN MENU] No Electron API available for file deletion, only localStorage deletion performed`);
|
|
console.log(`[MAIN MENU] Available electronAPI methods:`, Object.keys(window.electronAPI || {}));
|
|
}
|
|
|
|
// Clear from memory
|
|
console.log(`[MAIN MENU] Clearing save data from memory`);
|
|
this.saveData[this.selectedSlot] = null;
|
|
|
|
// Update UI
|
|
console.log(`[MAIN MENU] Updating UI after deletion`);
|
|
this.updateSaveSlots();
|
|
this.updateGameOptions();
|
|
|
|
console.log(`[MAIN MENU] Save data successfully deleted from slot ${this.selectedSlot}`);
|
|
|
|
// Show success message
|
|
this.showAlert(`Save data from slot ${this.selectedSlot} has been deleted successfully.`, 'success');
|
|
|
|
// Return to save selection screen
|
|
console.log(`[MAIN MENU] Returning to save selection screen`);
|
|
this.showSaveSection();
|
|
|
|
} catch (error) {
|
|
console.error('[MAIN MENU] Failed to delete save data:', error);
|
|
this.showAlert('Failed to delete save data. Please try again.', 'error');
|
|
}
|
|
}
|
|
|
|
loadGame(slotNumber) {
|
|
this.selectedSlot = slotNumber;
|
|
console.log(`[MAIN MENU] Loading game from slot ${slotNumber}`);
|
|
this.launchGame('continue');
|
|
}
|
|
|
|
async launchGame(mode) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('MainMenu.launchGame', {
|
|
mode: mode,
|
|
selectedSlot: this.selectedSlot,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
console.log('[MAIN MENU] Launching game in', mode, 'mode');
|
|
console.log('[MAIN MENU] Selected save slot:', this.selectedSlot);
|
|
|
|
try {
|
|
// Hide main menu
|
|
this.hide();
|
|
|
|
// Show loading screen
|
|
const loadingScreen = document.getElementById('loadingScreen');
|
|
if (loadingScreen) {
|
|
loadingScreen.classList.remove('hidden');
|
|
console.log('[MAIN MENU] Loading screen shown');
|
|
|
|
if (debugLogger) debugLogger.logStep('Loading screen displayed');
|
|
}
|
|
|
|
// Initialize game systems first
|
|
console.log('[MAIN MENU] Starting game systems initialization...');
|
|
|
|
if (debugLogger) debugLogger.logStep('Starting game systems initialization');
|
|
|
|
try {
|
|
await this.initializeGameSystems();
|
|
console.log('[MAIN MENU] Game systems initialized successfully');
|
|
|
|
if (debugLogger) debugLogger.logStep('Game systems initialized successfully');
|
|
|
|
// Set save slot in game engine
|
|
if (window.game) {
|
|
console.log('[MAIN MENU] Setting active save slot to:', this.selectedSlot);
|
|
|
|
// Pass save path information to game engine
|
|
if (this.savePaths) {
|
|
window.game.saveSlotInfo = {
|
|
slot: this.selectedSlot,
|
|
path: this.savePaths.slots[this.selectedSlot - 1],
|
|
useFileSystem: true
|
|
};
|
|
console.log('[MAIN MENU] Using file system for saves');
|
|
|
|
if (debugLogger) debugLogger.logStep('Save slot info set with file system', {
|
|
slot: this.selectedSlot,
|
|
path: this.savePaths.slots[this.selectedSlot - 1]
|
|
});
|
|
} else {
|
|
window.game.saveSlotInfo = {
|
|
slot: this.selectedSlot,
|
|
useFileSystem: false
|
|
};
|
|
console.log('[MAIN MENU] Using localStorage for saves');
|
|
|
|
if (debugLogger) debugLogger.logStep('Save slot info set with localStorage', {
|
|
slot: this.selectedSlot
|
|
});
|
|
}
|
|
|
|
// Start the game
|
|
if (mode === 'continue') {
|
|
console.log('[MAIN MENU] Starting game in continue mode');
|
|
|
|
if (debugLogger) debugLogger.logStep('Starting game in continue mode');
|
|
await window.game.startGame(true);
|
|
} else {
|
|
console.log('[MAIN MENU] Starting new game');
|
|
|
|
if (debugLogger) debugLogger.logStep('Starting new game');
|
|
await window.game.startGame(false);
|
|
}
|
|
|
|
// Perform immediate UI updates after game starts
|
|
console.log('[MAIN MENU] Performing immediate UI updates after game start');
|
|
|
|
// Update GUI immediately
|
|
if (window.game && window.game.updateGUI) {
|
|
console.log('[MAIN MENU] Updating GUI immediately');
|
|
window.game.updateGUI();
|
|
}
|
|
|
|
// Update daily countdown immediately
|
|
if (window.game && window.game.systems && window.game.systems.questSystem && window.game.systems.questSystem.updateDailyCountdown) {
|
|
console.log('[MAIN MENU] Updating daily countdown immediately');
|
|
window.game.systems.questSystem.updateDailyCountdown();
|
|
}
|
|
|
|
// Update weekly countdown immediately
|
|
if (window.game && window.game.systems && window.game.systems.questSystem && window.game.systems.questSystem.updateWeeklyCountdown) {
|
|
console.log('[MAIN MENU] Updating weekly countdown immediately');
|
|
window.game.systems.questSystem.updateWeeklyCountdown();
|
|
}
|
|
|
|
// Hide loading screen and show game interface
|
|
this.hideLoadingScreenAndShowGame();
|
|
|
|
if (debugLogger) debugLogger.endStep('MainMenu.launchGame', {
|
|
success: true,
|
|
mode: mode
|
|
});
|
|
} else {
|
|
throw new Error('Game engine not initialized');
|
|
}
|
|
} catch (error) {
|
|
console.error('[MAIN MENU] Game systems initialization failed:', error);
|
|
|
|
if (debugLogger) {
|
|
debugLogger.errorEvent('MainMenu.launchGame', error, {
|
|
phase: 'initialization',
|
|
mode: mode
|
|
});
|
|
debugLogger.endStep('MainMenu.launchGame', {
|
|
success: false,
|
|
error: error.message
|
|
});
|
|
}
|
|
|
|
// Show error and return to menu
|
|
this.showAlert('Failed to initialize game. Check console for details.\n\nError: ' + error.message, 'error');
|
|
this.show();
|
|
}
|
|
} catch (error) {
|
|
console.error('[MAIN MENU] Game systems initialization failed:', error);
|
|
|
|
if (debugLogger) {
|
|
debugLogger.errorEvent('MainMenu.launchGame', error, {
|
|
phase: 'initialization',
|
|
mode: mode
|
|
});
|
|
debugLogger.endStep('MainMenu.launchGame', {
|
|
success: false,
|
|
error: error.message
|
|
});
|
|
}
|
|
|
|
// Show error and return to menu
|
|
this.showAlert('Failed to initialize game. Check console for details.\n\nError: ' + error.message, 'error');
|
|
this.show();
|
|
}
|
|
}
|
|
|
|
async initializeGameSystems() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('MainMenu.initializeGameSystems', {
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
console.log('[MAIN MENU] Initializing game systems');
|
|
|
|
try {
|
|
// Initialize logger if available
|
|
const logger = window.logger;
|
|
if (logger) {
|
|
await logger.timeAsync('Game Systems Initialization', async () => {
|
|
await logger.info('Initializing game systems from main menu');
|
|
});
|
|
}
|
|
|
|
if (debugLogger) debugLogger.logStep('Creating GameEngine instance');
|
|
|
|
// Prevent duplicate GameEngine creation
|
|
if (window.game) {
|
|
console.log('[MAIN MENU] GameEngine already exists, skipping creation');
|
|
if (debugLogger) debugLogger.logStep('GameEngine already exists, skipping creation');
|
|
return;
|
|
}
|
|
|
|
// Create game engine
|
|
window.game = new GameEngine();
|
|
|
|
if (debugLogger) debugLogger.logStep('GameEngine created, calling init()');
|
|
|
|
// Initialize game systems
|
|
await window.game.init();
|
|
|
|
if (debugLogger) debugLogger.logStep('GameEngine init() completed successfully');
|
|
|
|
console.log('[MAIN MENU] Game systems initialized successfully');
|
|
|
|
if (debugLogger) debugLogger.endStep('MainMenu.initializeGameSystems', {
|
|
success: true
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('[MAIN MENU] Failed to initialize game systems:', error);
|
|
|
|
if (debugLogger) {
|
|
debugLogger.errorEvent('MainMenu.initializeGameSystems', error, {
|
|
phase: 'initialization',
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
debugLogger.endStep('MainMenu.initializeGameSystems', {
|
|
success: false,
|
|
error: error.message
|
|
});
|
|
}
|
|
|
|
// Show error and return to menu
|
|
this.showAlert('Failed to initialize game. Please try again.\n\nError: ' + error.message, 'error');
|
|
this.show();
|
|
}
|
|
}
|
|
|
|
showSettings() {
|
|
console.log('[MAIN MENU] Settings requested (placeholder)');
|
|
// Placeholder for settings menu
|
|
this.showAlert('Settings menu coming soon!', 'info');
|
|
}
|
|
|
|
showAbout() {
|
|
console.log('[MAIN MENU] About requested');
|
|
this.showAlert('Galaxy Strike Online\nVersion 1.0.0\n\nA space-themed idle MMORPG built with Electron.\n\n© 2024 Korvarix Studios', 'info', 'About');
|
|
}
|
|
|
|
showHelp() {
|
|
console.log('[MAIN MENU] Help requested');
|
|
this.showAlert('Galaxy Strike Online - Help\n\n• Login with your account to play\n• Select a save slot to store your progress\n• Start a new game or continue existing save\n• Use Ctrl+Alt+Shift+C for developer console\n\nFor more help, visit our Discord or documentation.', 'info', 'Help');
|
|
}
|
|
|
|
quitGame() {
|
|
console.log('[MAIN MENU] Quit requested');
|
|
|
|
this.showConfirm('Are you sure you want to quit Galaxy Strike Online?', () => {
|
|
// In Electron, this would close the app
|
|
if (window.electronAPI && window.electronAPI.quit) {
|
|
window.electronAPI.quit();
|
|
} else {
|
|
// Fallback for browser
|
|
window.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Public methods for external access
|
|
show() {
|
|
this.mainMenu?.classList.remove('hidden');
|
|
this.showSaveSection();
|
|
}
|
|
|
|
hide() {
|
|
this.mainMenu?.classList.add('hidden');
|
|
}
|
|
|
|
// Custom alert function to replace browser alerts
|
|
showAlert(message, type = 'info', title = null) {
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
const modal = document.getElementById('modal');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const modalBody = document.getElementById('modalBody');
|
|
|
|
console.log('[MAIN MENU] showAlert called', {
|
|
modalOverlay: !!modalOverlay,
|
|
modal: !!modal,
|
|
modalTitle: !!modalTitle,
|
|
modalBody: !!modalBody
|
|
});
|
|
|
|
if (!modalOverlay || !modal || !modalTitle || !modalBody) {
|
|
// Fallback to browser alert if modal elements aren't found
|
|
alert(message);
|
|
return;
|
|
}
|
|
|
|
// Set title based on type
|
|
const titles = {
|
|
'info': 'Information',
|
|
'success': 'Success',
|
|
'error': 'Error',
|
|
'warning': 'Warning'
|
|
};
|
|
|
|
const alertTitle = title || titles[type] || 'Information';
|
|
|
|
// Set modal content
|
|
modalTitle.textContent = alertTitle;
|
|
modalBody.innerHTML = `
|
|
<div class="alert-message">${message}</div>
|
|
<div class="modal-footer">
|
|
<button class="btn-alert" onclick="window.mainMenu.closeAlert()">OK</button>
|
|
</div>
|
|
`;
|
|
|
|
// Set modal type class
|
|
modal.className = `modal alert-modal ${type}`;
|
|
|
|
// Show modal
|
|
modalOverlay.classList.remove('hidden');
|
|
|
|
// Add click outside to close
|
|
modalOverlay.onclick = (e) => {
|
|
if (e.target === modalOverlay) {
|
|
this.closeAlert();
|
|
}
|
|
};
|
|
|
|
// Add escape key to close
|
|
const handleEscape = (e) => {
|
|
if (e.key === 'Escape') {
|
|
this.closeAlert();
|
|
document.removeEventListener('keydown', handleEscape);
|
|
}
|
|
};
|
|
document.addEventListener('keydown', handleEscape);
|
|
}
|
|
|
|
closeAlert() {
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
if (modalOverlay) {
|
|
modalOverlay.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
// Custom confirmation function to replace browser confirm()
|
|
showConfirm(message, onConfirm, onCancel = null) {
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
const modal = document.getElementById('modal');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const modalBody = document.getElementById('modalBody');
|
|
|
|
console.log('[MAIN MENU] showConfirm called', {
|
|
modalOverlay: !!modalOverlay,
|
|
modal: !!modal,
|
|
modalTitle: !!modalTitle,
|
|
modalBody: !!modalBody
|
|
});
|
|
|
|
if (!modalOverlay || !modal || !modalTitle || !modalBody) {
|
|
console.warn('[MAIN MENU] Modal elements not found, falling back to browser confirm');
|
|
// Fallback to browser confirm if modal elements aren't found
|
|
const result = confirm(message);
|
|
if (result && onConfirm) onConfirm();
|
|
if (!result && onCancel) onCancel();
|
|
return;
|
|
}
|
|
|
|
// Set modal content
|
|
modalTitle.textContent = 'Confirm Action';
|
|
modalBody.innerHTML = `
|
|
<div class="confirm-message">${message}</div>
|
|
<div class="modal-footer">
|
|
<button class="btn-cancel" onclick="window.mainMenu.closeConfirm()">Cancel</button>
|
|
<button class="btn-confirm" onclick="window.mainMenu.executeConfirm()">Confirm</button>
|
|
</div>
|
|
`;
|
|
|
|
// Set modal type class
|
|
modal.className = 'modal confirmation-modal';
|
|
|
|
// Store callbacks
|
|
this._confirmCallback = onConfirm;
|
|
this._cancelCallback = onCancel;
|
|
|
|
// Show modal
|
|
modalOverlay.classList.remove('hidden');
|
|
|
|
// Add click outside to close
|
|
modalOverlay.onclick = (e) => {
|
|
if (e.target === modalOverlay) {
|
|
this.closeConfirm();
|
|
}
|
|
};
|
|
|
|
// Add escape key to close
|
|
const handleEscape = (e) => {
|
|
if (e.key === 'Escape') {
|
|
this.closeConfirm();
|
|
document.removeEventListener('keydown', handleEscape);
|
|
}
|
|
};
|
|
document.addEventListener('keydown', handleEscape);
|
|
}
|
|
|
|
executeConfirm() {
|
|
console.log('[MAIN MENU] executeConfirm called', {
|
|
hasCallback: !!this._confirmCallback
|
|
});
|
|
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
if (modalOverlay) {
|
|
modalOverlay.classList.add('hidden');
|
|
}
|
|
|
|
if (this._confirmCallback) {
|
|
console.log('[MAIN MENU] Executing confirmation callback');
|
|
this._confirmCallback();
|
|
} else {
|
|
console.warn('[MAIN MENU] No confirmation callback found');
|
|
}
|
|
|
|
// Clear callbacks
|
|
this._confirmCallback = null;
|
|
this._cancelCallback = null;
|
|
}
|
|
|
|
closeConfirm() {
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
if (modalOverlay) {
|
|
modalOverlay.classList.add('hidden');
|
|
}
|
|
|
|
if (this._cancelCallback) {
|
|
this._cancelCallback();
|
|
}
|
|
|
|
// Clear callbacks
|
|
this._confirmCallback = null;
|
|
this._cancelCallback = null;
|
|
}
|
|
}
|
|
|
|
// Initialize main menu when DOM is ready
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
console.log('[MAIN MENU] DOMContentLoaded event fired');
|
|
window.mainMenu = new MainMenu();
|
|
});
|
|
|
|
// Also try immediate initialization if DOM is already loaded
|
|
if (document.readyState === 'loading') {
|
|
console.log('[MAIN MENU] DOM still loading, waiting for DOMContentLoaded');
|
|
} else {
|
|
console.log('[MAIN MENU] DOM already loaded, initializing immediately');
|
|
window.mainMenu = new MainMenu();
|
|
}
|