shared-folder: externalize gallery view JS & enforce CSP compliance
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,6 +1,6 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Changes 4/27/2025
|
## Changes 4/27/2025 1.2.7
|
||||||
|
|
||||||
- **Select-All** checkbox now correctly toggles all `.file-checkbox` inputs
|
- **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
|
- 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
|
- 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 Pagination controls & Items-per-page dropdown
|
||||||
- Fixed `#advancedSearchToggle` in both `renderFileTable()` and `renderGalleryView()`
|
- 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
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { sendRequest } from './networkUtils.js';
|
|||||||
import { t, applyTranslations, setLocale } from './i18n.js';
|
import { t, applyTranslations, setLocale } from './i18n.js';
|
||||||
import { loadAdminConfigFunc } from './auth.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>`;
|
const adminTitle = `${t("admin_panel")} <small style="font-size: 12px; color: gray;">${version}</small>`;
|
||||||
|
|
||||||
let lastLoginData = null;
|
let lastLoginData = null;
|
||||||
|
|||||||
60
public/js/sharedFolderView.js
Normal file
60
public/js/sharedFolderView.js
Normal 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;
|
||||||
|
});
|
||||||
@@ -550,13 +550,18 @@ class FolderController
|
|||||||
body {
|
body {
|
||||||
background: #f2f2f2;
|
background: #f2f2f2;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
padding: 20px;
|
padding: 0px 20px 20px 20px;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -661,6 +666,28 @@ class FolderController
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: #777;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -670,7 +697,7 @@ class FolderController
|
|||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Toggle Button -->
|
<!-- 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 -->
|
<!-- List View Container -->
|
||||||
<div id="listViewContainer">
|
<div id="listViewContainer">
|
||||||
@@ -757,86 +784,14 @@ class FolderController
|
|||||||
<div class="footer">
|
<div class="footer">
|
||||||
© <?php echo date("Y"); ?> FileRise. All rights reserved.
|
© <?php echo date("Y"); ?> FileRise. All rights reserved.
|
||||||
</div>
|
</div>
|
||||||
|
<!-- non-executing JSON payload, never blocked by CSP -->
|
||||||
<script>
|
<script type="application/json" id="shared-data">
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
{
|
||||||
// JavaScript for toggling view modes (list/gallery) and wiring up gallery clicks
|
"token": <?php echo json_encode($token, JSON_HEX_TAG); ?>,
|
||||||
var viewMode = 'list';
|
"files": <?php echo json_encode($files, JSON_HEX_TAG); ?>
|
||||||
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;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/js/sharedFolderView.js" defer></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user