Fix image management screen freeze with performance optimization

Major performance improvements:
- Replaced expensive DOM cloning/replacing in setupImageManagementEventListeners()
- Used direct onclick assignments instead of clone/replace operations
- Added imageManagementListenersAttached flag to prevent duplicate listener attachment
- Simplified updateImageGalleryControls() to use direct onclick assignment
- Added comprehensive logging to track function execution flow
- Reset listener flag when showing image management screen for fresh attachment

Performance fixes:
- Eliminated heavy DOM manipulation that was causing UI freeze
- Reduced memory overhead from constant node cloning
- Prevented listener duplication without expensive DOM operations
- Faster event listener setup with direct property assignment

The freeze was caused by the expensive cloneNode() and replaceChild() operations
being performed on every screen load, creating performance bottlenecks.
This commit is contained in:
fritzsenpai 2025-09-25 21:06:27 -05:00
parent aa3b7d8a1c
commit 3d949fe08c
1 changed files with 50 additions and 70 deletions

120
game.js
View File

@ -26,6 +26,7 @@ class TaskChallengeGame {
this.timerInterval = null;
this.imageDiscoveryComplete = false;
this.imageManagementListenersAttached = false;
this.musicManager = new MusicManager(this.dataManager);
this.initializeEventListeners();
this.setupKeyboardShortcuts();
@ -850,6 +851,10 @@ class TaskChallengeGame {
// Image Management Methods
showImageManagement() {
console.log('showImageManagement() called');
// Reset listener flag to allow fresh attachment
this.imageManagementListenersAttached = false;
this.showScreen('image-management-screen');
console.log('Screen switched to image-management-screen');
this.setupImageManagementEventListeners();
@ -904,129 +909,104 @@ class TaskChallengeGame {
}
updateImageGalleryControls(activeTab) {
console.log('updateImageGalleryControls() called for tab:', activeTab);
// Update the select/deselect/delete buttons to work with the active tab
const selectAllBtn = document.getElementById('select-all-images-btn');
const deselectAllBtn = document.getElementById('deselect-all-images-btn');
const deleteBtn = document.getElementById('delete-selected-btn');
if (selectAllBtn) {
const newSelectAllBtn = selectAllBtn.cloneNode(true);
selectAllBtn.parentNode.replaceChild(newSelectAllBtn, selectAllBtn);
newSelectAllBtn.addEventListener('click', () => this.selectAllImages(activeTab));
selectAllBtn.onclick = () => this.selectAllImages(activeTab);
}
if (deselectAllBtn) {
const newDeselectAllBtn = deselectAllBtn.cloneNode(true);
deselectAllBtn.parentNode.replaceChild(newDeselectAllBtn, deselectAllBtn);
newDeselectAllBtn.addEventListener('click', () => this.deselectAllImages(activeTab));
deselectAllBtn.onclick = () => this.deselectAllImages(activeTab);
}
if (deleteBtn) {
const newDeleteBtn = deleteBtn.cloneNode(true);
deleteBtn.parentNode.replaceChild(newDeleteBtn, deleteBtn);
newDeleteBtn.addEventListener('click', () => this.deleteSelectedImages(activeTab));
deleteBtn.onclick = () => this.deleteSelectedImages(activeTab);
}
console.log('Gallery controls updated for:', activeTab);
}
setupImageManagementEventListeners() {
// Remove any existing listeners to prevent duplicates
console.log('setupImageManagementEventListeners() called');
// Check if we already have listeners attached to prevent duplicates
if (this.imageManagementListenersAttached) {
console.log('Image management listeners already attached, skipping...');
return;
}
console.log('Setting up image management event listeners...');
// Back button
const backBtn = document.getElementById('back-to-start-from-images-btn');
const uploadBtn = document.getElementById('upload-images-btn');
const uploadInput = document.getElementById('image-upload-input');
const storageInfoBtn = document.getElementById('storage-info-btn');
const selectAllBtn = document.getElementById('select-all-images-btn');
const deselectAllBtn = document.getElementById('deselect-all-images-btn');
const deleteBtn = document.getElementById('delete-selected-btn');
const taskImagesTab = document.getElementById('task-images-tab');
const consequenceImagesTab = document.getElementById('consequence-images-tab');
// Desktop-specific buttons
const importTaskBtn = document.getElementById('import-task-images-btn');
const importConsequenceBtn = document.getElementById('import-consequence-images-btn');
// Clone and replace to remove existing listeners
if (backBtn) {
const newBackBtn = backBtn.cloneNode(true);
backBtn.parentNode.replaceChild(newBackBtn, backBtn);
newBackBtn.addEventListener('click', () => this.showScreen('start-screen'));
backBtn.onclick = () => this.showScreen('start-screen');
}
// Desktop import buttons
const importTaskBtn = document.getElementById('import-task-images-btn');
if (importTaskBtn) {
const newImportTaskBtn = importTaskBtn.cloneNode(true);
importTaskBtn.parentNode.replaceChild(newImportTaskBtn, importTaskBtn);
newImportTaskBtn.addEventListener('click', async () => {
importTaskBtn.onclick = async () => {
console.log('Import task images clicked');
if (this.fileManager) {
await this.fileManager.selectAndImportImages('task');
this.loadImageGallery(); // Refresh the gallery to show new images
} else {
this.showNotification('Desktop file manager not available', 'warning');
}
});
};
}
const importConsequenceBtn = document.getElementById('import-consequence-images-btn');
if (importConsequenceBtn) {
const newImportConsequenceBtn = importConsequenceBtn.cloneNode(true);
importConsequenceBtn.parentNode.replaceChild(newImportConsequenceBtn, importConsequenceBtn);
newImportConsequenceBtn.addEventListener('click', async () => {
importConsequenceBtn.onclick = async () => {
console.log('Import consequence images clicked');
if (this.fileManager) {
await this.fileManager.selectAndImportImages('consequence');
this.loadImageGallery(); // Refresh the gallery to show new images
} else {
this.showNotification('Desktop file manager not available', 'warning');
}
});
};
}
// Original web upload button (fallback)
if (uploadBtn) {
const newUploadBtn = uploadBtn.cloneNode(true);
uploadBtn.parentNode.replaceChild(newUploadBtn, uploadBtn);
newUploadBtn.addEventListener('click', () => this.uploadImages());
}
// Storage info button
const storageInfoBtn = document.getElementById('storage-info-btn');
if (storageInfoBtn) {
const newStorageInfoBtn = storageInfoBtn.cloneNode(true);
storageInfoBtn.parentNode.replaceChild(newStorageInfoBtn, storageInfoBtn);
newStorageInfoBtn.addEventListener('click', () => this.showStorageInfo());
storageInfoBtn.onclick = () => this.showStorageInfo();
}
// Tab buttons
const taskImagesTab = document.getElementById('task-images-tab');
if (taskImagesTab) {
const newTaskImagesTab = taskImagesTab.cloneNode(true);
taskImagesTab.parentNode.replaceChild(newTaskImagesTab, taskImagesTab);
newTaskImagesTab.addEventListener('click', () => this.switchImageTab('task'));
taskImagesTab.onclick = () => this.switchImageTab('task');
}
const consequenceImagesTab = document.getElementById('consequence-images-tab');
if (consequenceImagesTab) {
const newConsequenceImagesTab = consequenceImagesTab.cloneNode(true);
consequenceImagesTab.parentNode.replaceChild(newConsequenceImagesTab, consequenceImagesTab);
newConsequenceImagesTab.addEventListener('click', () => this.switchImageTab('consequence'));
consequenceImagesTab.onclick = () => this.switchImageTab('consequence');
}
// Upload input (fallback for web mode)
const uploadInput = document.getElementById('image-upload-input');
if (uploadInput) {
const newUploadInput = uploadInput.cloneNode(true);
uploadInput.parentNode.replaceChild(newUploadInput, uploadInput);
newUploadInput.addEventListener('change', (e) => this.handleImageUpload(e));
uploadInput.onchange = (e) => this.handleImageUpload(e);
}
if (selectAllBtn) {
const newSelectAllBtn = selectAllBtn.cloneNode(true);
selectAllBtn.parentNode.replaceChild(newSelectAllBtn, selectAllBtn);
newSelectAllBtn.addEventListener('click', () => this.selectAllImages());
// Web upload button (fallback)
const uploadBtn = document.getElementById('upload-images-btn');
if (uploadBtn) {
uploadBtn.onclick = () => this.uploadImages();
}
if (deselectAllBtn) {
const newDeselectAllBtn = deselectAllBtn.cloneNode(true);
deselectAllBtn.parentNode.replaceChild(newDeselectAllBtn, deselectAllBtn);
newDeselectAllBtn.addEventListener('click', () => this.deselectAllImages());
}
if (deleteBtn) {
const newDeleteBtn = deleteBtn.cloneNode(true);
deleteBtn.parentNode.replaceChild(newDeleteBtn, deleteBtn);
newDeleteBtn.addEventListener('click', () => this.deleteSelectedImages());
}
// Mark listeners as attached
this.imageManagementListenersAttached = true;
console.log('setupImageManagementEventListeners() completed');
}
loadImageGallery() {