diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e33f3d..cf9e077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Added `.toggle-btn` CSS for blue header-style toggle button and applied it in JS - Added `.pagination a:hover { background-color: #0056b3; }` to match button hover - Tweaked `body` padding and `header h1` margins to reduce whitespace above header + - Refactored `sharedFolderView.js:renderGalleryView()` to eliminate `innerHTML` usage; now uses `document.createElement` and `textContent` so filenames and URLs are fully escaped and CSP-safe --- diff --git a/public/js/sharedFolderView.js b/public/js/sharedFolderView.js index 8bd4fea..b58a7a1 100644 --- a/public/js/sharedFolderView.js +++ b/public/js/sharedFolderView.js @@ -2,19 +2,17 @@ document.addEventListener('DOMContentLoaded', function() { let viewMode = 'list'; const payload = JSON.parse( - document.getElementById('shared-data').textContent - ); - const token = payload.token; - const filesData = payload.files; + document.getElementById('shared-data').textContent + ); + const token = payload.token; + const filesData = payload.files; const downloadBase = `${window.location.origin}/api/folder/downloadSharedFile.php?token=${encodeURIComponent(token)}&file=`; + const btn = document.getElementById('toggleBtn'); + if (btn) btn.classList.add('toggle-btn'); function toggleViewMode() { const listEl = document.getElementById('listViewContainer'); const galleryEl = document.getElementById('galleryViewContainer'); - const btn = document.getElementById('toggleBtn'); - if (btn) { - btn.classList.add('toggle-btn'); - } if (viewMode === 'list') { viewMode = 'gallery'; @@ -30,30 +28,62 @@ document.addEventListener('DOMContentLoaded', function() { } } - document.getElementById('toggleBtn').addEventListener('click', toggleViewMode); + btn.addEventListener('click', toggleViewMode); function renderGalleryView() { - const galleryContainer = document.getElementById('galleryViewContainer'); - let html = '
'; - galleryContainer.innerHTML = html; + const isImg = /^(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/.test(ext); - galleryContainer.querySelectorAll('.gallery-preview') - .forEach(el => el.addEventListener('click', () => { - window.location.href = el.dataset.url; - })); + // card + const card = document.createElement('div'); + card.className = 'shared-gallery-card'; + + // preview + const preview = document.createElement('div'); + preview.className = 'gallery-preview'; + preview.style.cursor = 'pointer'; + preview.dataset.url = url; + + if (isImg) { + const img = document.createElement('img'); + img.src = url; + img.alt = file; // safe, file is not HTML + preview.appendChild(img); + } else { + const icon = document.createElement('span'); + icon.className = 'material-icons'; + icon.textContent = 'insert_drive_file'; + preview.appendChild(icon); + } + card.appendChild(preview); + + // info + const info = document.createElement('div'); + info.className = 'gallery-info'; + const nameSpan = document.createElement('span'); + nameSpan.className = 'gallery-file-name'; + nameSpan.textContent = file; // textContent escapes any HTML + info.appendChild(nameSpan); + card.appendChild(info); + + grid.appendChild(card); + + preview.addEventListener('click', () => { + window.location.href = preview.dataset.url; + }); + }); + + container.appendChild(grid); } window.renderGalleryView = renderGalleryView;