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:
parent
aa3b7d8a1c
commit
3d949fe08c
120
game.js
120
game.js
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue