From 7892df21ecd5ad8ece7092c8a5e99d28abe92b0b Mon Sep 17 00:00:00 2001 From: Will Miao Date: Sun, 26 Oct 2025 10:52:24 +0800 Subject: [PATCH] feat: add dynamic loading overlay creation with accessibility Add fallback DOM element creation in LoadingManager constructor to handle cases where loading overlay elements don't exist in the DOM. This ensures the loading functionality works even when the required HTML elements are missing. - Create loading overlay, content container, progress bar, and status text elements dynamically - Add ARIA attributes to progress bar for accessibility - Move details container insertion to use the created loadingContent reference - Maintain existing functionality while adding robustness for missing DOM elements --- static/js/managers/LoadingManager.js | 41 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/static/js/managers/LoadingManager.js b/static/js/managers/LoadingManager.js index 00c333a6..c1743730 100644 --- a/static/js/managers/LoadingManager.js +++ b/static/js/managers/LoadingManager.js @@ -5,8 +5,40 @@ import { formatFileSize } from '../utils/formatters.js'; export class LoadingManager { constructor() { this.overlay = document.getElementById('loading-overlay'); - this.progressBar = this.overlay.querySelector('.progress-bar'); - this.statusText = this.overlay.querySelector('.loading-status'); + + if (!this.overlay) { + this.overlay = document.createElement('div'); + this.overlay.id = 'loading-overlay'; + this.overlay.style.display = 'none'; + document.body.appendChild(this.overlay); + } + + this.loadingContent = this.overlay.querySelector('.loading-content'); + if (!this.loadingContent) { + this.loadingContent = document.createElement('div'); + this.loadingContent.className = 'loading-content'; + this.overlay.appendChild(this.loadingContent); + } + + this.progressBar = this.loadingContent.querySelector('.progress-bar'); + if (!this.progressBar) { + this.progressBar = document.createElement('div'); + this.progressBar.className = 'progress-bar'; + this.progressBar.setAttribute('role', 'progressbar'); + this.progressBar.setAttribute('aria-valuemin', '0'); + this.progressBar.setAttribute('aria-valuemax', '100'); + this.progressBar.setAttribute('aria-valuenow', '0'); + this.progressBar.style.width = '0%'; + this.loadingContent.appendChild(this.progressBar); + } + + this.statusText = this.loadingContent.querySelector('.loading-status'); + if (!this.statusText) { + this.statusText = document.createElement('div'); + this.statusText.className = 'loading-status'; + this.loadingContent.appendChild(this.statusText); + } + this.detailsContainer = null; // Will be created when needed } @@ -51,9 +83,8 @@ export class LoadingManager { this.detailsContainer.className = 'progress-details-container'; // Insert after the main progress bar - const loadingContent = this.overlay.querySelector('.loading-content'); - if (loadingContent) { - loadingContent.appendChild(this.detailsContainer); + if (this.loadingContent) { + this.loadingContent.appendChild(this.detailsContainer); } return this.detailsContainer;