shared-folder: externalize gallery view JS & enforce CSP compliance

This commit is contained in:
Ryan
2025-04-27 18:18:00 -04:00
committed by GitHub
parent 18f588dc24
commit 76f5ed5c96
4 changed files with 109 additions and 83 deletions

View File

@@ -1,6 +1,6 @@
# Changelog
## Changes 4/27/2025
## Changes 4/27/2025 1.2.7
- **Select-All** checkbox now correctly toggles all `.file-checkbox` inputs
- Updated `toggleAllCheckboxes(masterCheckbox)` to call `updateRowHighlight()` on each row so selections get the `.row-selected` highlight
@@ -8,6 +8,17 @@
- Enhanced `updateFileActionButtons()` to set the header checkbox to checked, unchecked, or indeterminate based on how many files are selected
- Fixed Pagination controls & Items-per-page dropdown
- Fixed `#advancedSearchToggle` in both `renderFileTable()` and `renderGalleryView()`
- **Shared folder gallery view logic**
- Introduced new `public/js/sharedFolderView.js` containing all DOMContentLoaded wiring, `toggleViewMode()`, gallery rendering, and event listeners
- Embedded a non-executing JSON payload in `shareFolder.php`
- **`FolderController::shareFolder()` / `shareFolder.php`**
- Removed all inline `onclick="…"` attributes and inline `<script>` blocks
- Added `<script type="application/json" id="shared-data">…</script>` to export `$token` and `$files`
- Added `<script src="/js/sharedFolderView.js" defer></script>` to load the external view logic
- **Styling updates**
- 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
---

View File

@@ -3,7 +3,7 @@ import { sendRequest } from './networkUtils.js';
import { t, applyTranslations, setLocale } from './i18n.js';
import { loadAdminConfigFunc } from './auth.js';
const version = "v1.2.6"; // Update this version string as needed
const version = "v1.2.7"; // Update this version string as needed
const adminTitle = `${t("admin_panel")} <small style="font-size: 12px; color: gray;">${version}</small>`;
let lastLoginData = null;

View File

@@ -0,0 +1,60 @@
// sharedFolderView.js
document.addEventListener('DOMContentLoaded', function() {
let viewMode = 'list';
const payload = JSON.parse(
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=`;
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';
listEl.style.display = 'none';
renderGalleryView();
galleryEl.style.display = 'block';
btn.textContent = 'Switch to List View';
} else {
viewMode = 'list';
galleryEl.style.display = 'none';
listEl.style.display = 'block';
btn.textContent = 'Switch to Gallery View';
}
}
document.getElementById('toggleBtn').addEventListener('click', toggleViewMode);
function renderGalleryView() {
const galleryContainer = document.getElementById('galleryViewContainer');
let html = '<div class="shared-gallery-container">';
filesData.forEach(file => {
const url = downloadBase + encodeURIComponent(file);
const ext = file.split('.').pop().toLowerCase();
const thumb = /^(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/.test(ext)
? `<img src="${url}" alt="${file}">`
: `<span class="material-icons">insert_drive_file</span>`;
html += `
<div class="shared-gallery-card">
<div class="gallery-preview" data-url="${url}" style="cursor:pointer;">${thumb}</div>
<div class="gallery-info"><span class="gallery-file-name">${file}</span></div>
</div>`;
});
html += '</div>';
galleryContainer.innerHTML = html;
galleryContainer.querySelectorAll('.gallery-preview')
.forEach(el => el.addEventListener('click', () => {
window.location.href = el.dataset.url;
}));
}
window.renderGalleryView = renderGalleryView;
});

View File

@@ -550,13 +550,18 @@ class FolderController
body {
background: #f2f2f2;
font-family: Arial, sans-serif;
padding: 20px;
padding: 0px 20px 20px 20px;
color: #333;
}
.header {
text-align: center;
margin-bottom: 30px;
margin-top: 0;
}
.header h1 {
margin-top: 0;
}
.container {
@@ -661,6 +666,28 @@ class FolderController
font-size: 0.9rem;
color: #777;
}
.toggle-btn {
background-color: #007BFF;
color: #fff;
border: none;
border-radius: 4px;
padding: 8px 16px;
font-size: 1rem;
cursor: pointer;
}
.toggle-btn:hover {
background-color: #0056b3;
}
.pagination a:hover {
background-color: #0056b3;
}
.pagination span {
cursor: default;
}
</style>
</head>
@@ -670,7 +697,7 @@ class FolderController
</div>
<div class="container">
<!-- Toggle Button -->
<button id="toggleBtn" class="toggle-btn" onclick="toggleViewMode()">Switch to Gallery View</button>
<button id="toggleBtn" class="toggle-btn">Switch to Gallery View</button>
<!-- List View Container -->
<div id="listViewContainer">
@@ -757,86 +784,14 @@ class FolderController
<div class="footer">
&copy; <?php echo date("Y"); ?> FileRise. All rights reserved.
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// JavaScript for toggling view modes (list/gallery) and wiring up gallery clicks
var viewMode = 'list';
var token = '<?php echo addslashes($token); ?>';
var filesData = <?php echo json_encode($files); ?>;
// Build the download URL base
var downloadBase = window.location.origin +
'/api/folder/downloadSharedFile.php?token=' +
encodeURIComponent(token) +
'&file=';
function toggleViewMode() {
var listEl = document.getElementById('listViewContainer');
var galleryEl = document.getElementById('galleryViewContainer');
var btn = document.getElementById('toggleBtn');
if (viewMode === 'list') {
viewMode = 'gallery';
listEl.style.display = 'none';
renderGalleryView();
galleryEl.style.display = 'block';
btn.textContent = 'Switch to List View';
} else {
viewMode = 'list';
galleryEl.style.display = 'none';
listEl.style.display = 'block';
btn.textContent = 'Switch to Gallery View';
}
}
// Wire up the toggle button
document.getElementById('toggleBtn')
.addEventListener('click', toggleViewMode);
function renderGalleryView() {
var galleryContainer = document.getElementById('galleryViewContainer');
var html = '<div class="shared-gallery-container">';
filesData.forEach(function(file) {
var encodedName = encodeURIComponent(file);
var fileUrl = downloadBase + encodedName;
var ext = file.split('.').pop().toLowerCase();
var thumb;
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'].indexOf(ext) >= 0) {
thumb = '<img src="' + fileUrl + '" alt="' + file + '">';
} else {
thumb = '<span class="material-icons">insert_drive_file</span>';
}
html +=
'<div class="shared-gallery-card">' +
'<div class="gallery-preview" data-url="' + fileUrl + '" style="cursor:pointer;">' +
thumb +
'</div>' +
'<div class="gallery-info">' +
'<span class="gallery-file-name">' + file + '</span>' +
'</div>' +
'</div>';
});
html += '</div>';
galleryContainer.innerHTML = html;
// Wire up each thumbnail click
galleryContainer.querySelectorAll('.gallery-preview')
.forEach(function(el) {
el.addEventListener('click', function() {
window.location.href = el.dataset.url;
});
});
}
// Expose for manual invocation if needed
window.renderGalleryView = renderGalleryView;
});
<!-- non-executing JSON payload, never blocked by CSP -->
<script type="application/json" id="shared-data">
{
"token": <?php echo json_encode($token, JSON_HEX_TAG); ?>,
"files": <?php echo json_encode($files, JSON_HEX_TAG); ?>
}
</script>
<script src="/js/sharedFolderView.js" defer></script>
</body>
</html>