Improve PDF preview and input focus behaviors

This commit is contained in:
Ryan
2025-04-30 00:53:44 -04:00
committed by GitHub
parent 2e4dbe7f7f
commit 274bedd186
5 changed files with 101 additions and 55 deletions

View File

@@ -1,5 +1,15 @@
# Changelog
## Changes 4/30/2025 v1.2.8
- **Added** PDF preview in `filePreview.js` (the `extension === "pdf"` block): replaced in-modal `<embed>` with `window.open(urlWithTs, "_blank")` and closed the modal to avoid CSP `frame-ancestors 'none'` restrictions.
- **Added** `autofocus` attribute to the login forms username input (`#loginUsername`) so the cursor is ready for typing on page load.
- **Enhanced** login initialization with a `DOMContentLoaded` fallback that calls `loginUsername.focus()` (via `setTimeout`) if needed.
- **Set** focus to the “New Username” field (`#newUsername`) when entering setup mode, hiding the login form and showing the Add-User modal.
- **Implemented** Enter-key support in setup mode by attaching `attachEnterKeyListener("addUserModal", "saveUserBtn")`, allowing users to press Enter to submit the Add-User form.
---
## Changes 4/28/2025
**Added**
@@ -28,7 +38,7 @@
- OpenAPI annotations for both endpoints updated to require `expirationValue` + `expirationUnit` (enum: seconds, minutes, hours, days)
## Changes 4/27/2025 1.2.7
## Changes 4/27/2025 v1.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

View File

@@ -182,7 +182,7 @@
<form id="authForm" method="post">
<div class="form-group">
<label for="loginUsername" data-i18n-key="user">User:</label>
<input type="text" class="form-control" id="loginUsername" name="username" required />
<input type="text" class="form-control" id="loginUsername" name="username" required autofocus />
</div>
<div class="form-group">
<label for="loginPassword" data-i18n-key="password">Password:</label>
@@ -442,18 +442,30 @@
<div id="addUserModal" class="modal">
<div class="modal-content">
<h3 data-i18n-key="create_new_user_title">Create New User</h3>
<label for="newUsername" data-i18n-key="username">Username:</label>
<input type="text" id="newUsername" class="form-control" />
<label for="addUserPassword" data-i18n-key="password">Password:</label>
<input type="password" id="addUserPassword" class="form-control" />
<div id="adminCheckboxContainer">
<input type="checkbox" id="isAdmin" />
<label for="isAdmin" data-i18n-key="grant_admin">Grant Admin Access</label>
</div>
<div class="button-container">
<button id="cancelUserBtn" class="btn btn-secondary" data-i18n-key="cancel">Cancel</button>
<button id="saveUserBtn" class="btn btn-primary" data-i18n-key="save_user">Save User</button>
</div>
<!-- 1) Add a form around these fields -->
<form id="addUserForm">
<label for="newUsername" data-i18n-key="username">Username:</label>
<input type="text" id="newUsername" class="form-control" required />
<label for="addUserPassword" data-i18n-key="password">Password:</label>
<input type="password" id="addUserPassword" class="form-control" required />
<div id="adminCheckboxContainer">
<input type="checkbox" id="isAdmin" />
<label for="isAdmin" data-i18n-key="grant_admin">Grant Admin Access</label>
</div>
<div class="button-container">
<!-- Cancel stays type="button" -->
<button type="button" id="cancelUserBtn" class="btn btn-secondary" data-i18n-key="cancel">
Cancel
</button>
<!-- Save becomes type="submit" -->
<button type="submit" id="saveUserBtn" class="btn btn-primary" data-i18n-key="save_user">
Save User
</button>
</div>
</form>
</div>
</div>
<div id="removeUserModal" class="modal">

View File

@@ -125,10 +125,17 @@ function updateItemsPerPageSelect() {
}
}
function updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }) {
const authForm = document.getElementById("authForm");
if (authForm) authForm.style.display = disableFormLogin ? "none" : "block";
if
(authForm) {
authForm.style.display = disableFormLogin ? "none" : "block";
setTimeout(() => {
const loginInput = document.getElementById('loginUsername');
if (loginInput) loginInput.focus();
}, 0);
}
const basicAuthLink = document.querySelector("a[href='/api/auth/login_basic.php']");
if (basicAuthLink) basicAuthLink.style.display = disableBasicAuth ? "none" : "inline-block";
const oidcLoginBtn = document.getElementById("oidcLoginBtn");
@@ -187,7 +194,7 @@ function updateAuthenticatedUI(data) {
toggleVisibility("mainOperations", true);
toggleVisibility("uploadFileForm", true);
toggleVisibility("fileListContainer", true);
attachEnterKeyListener("addUserModal", "saveUserBtn");
//attachEnterKeyListener("addUserModal", "saveUserBtn");
attachEnterKeyListener("removeUserModal", "deleteUserBtn");
attachEnterKeyListener("changePasswordModal", "saveNewPasswordBtn");
document.querySelector(".header-buttons").style.visibility = "visible";
@@ -443,34 +450,46 @@ function initAuth() {
toggleVisibility("addUserModal", true);
document.getElementById("newUsername").focus();
});
document.getElementById("saveUserBtn").addEventListener("click", function () {
const newUsername = document.getElementById("newUsername").value.trim();
const newPassword = document.getElementById("addUserPassword").value.trim();
const isAdmin = document.getElementById("isAdmin").checked;
if (!newUsername || !newPassword) {
showToast("Username and password are required!");
return;
}
let url = "/api/addUser.php";
if (window.setupMode) url += "?setup=1";
fetchWithCsrf(url, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
// remove your old saveUserBtn click-handler…
// instead:
const addUserForm = document.getElementById("addUserForm");
addUserForm.addEventListener("submit", function (e) {
e.preventDefault(); // stop the browser from reloading the page
const newUsername = document.getElementById("newUsername").value.trim();
const newPassword = document.getElementById("addUserPassword").value.trim();
const isAdmin = document.getElementById("isAdmin").checked;
if (!newUsername || !newPassword) {
showToast("Username and password are required!");
return;
}
let url = "/api/addUser.php";
if (window.setupMode) url += "?setup=1";
fetchWithCsrf(url, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
})
.then(r => r.json())
.then(data => {
if (data.success) {
showToast("User added successfully!");
closeAddUserModal();
checkAuthentication(false);
} else {
showToast("Error: " + (data.error || "Could not add user"));
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast("User added successfully!");
closeAddUserModal();
checkAuthentication(false);
} else {
showToast("Error: " + (data.error || "Could not add user"));
}
})
.catch(() => { });
});
.catch(() => {
showToast("Error: Could not add user");
});
});
document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal);
document.getElementById("removeUserBtn").addEventListener("click", function () {

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.7"; // Update this version string as needed
const version = "v1.2.8"; // 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

@@ -416,16 +416,21 @@ export function previewFile(fileUrl, fileName) {
}
} else {
// Handle non-image file previews.
if (extension === "pdf") {
const embed = document.createElement("embed");
const separator = fileUrl.indexOf('?') === -1 ? '?' : '&';
embed.src = fileUrl + separator + 't=' + new Date().getTime();
embed.type = "application/pdf";
embed.style.width = "80vw";
embed.style.height = "80vh";
embed.style.border = "none";
container.appendChild(embed);
} else if (/\.(mp4|mkv|webm|mov|ogv)$/i.test(fileName)) {
if (extension === "pdf") {
// build a cachebusted URL
const separator = fileUrl.includes('?') ? '&' : '?';
const urlWithTs = fileUrl + separator + 't=' + Date.now();
// open in a new tab (avoids CSP frame-ancestors)
window.open(urlWithTs, "_blank");
// tear down the just-created modal
const modal = document.getElementById("filePreviewModal");
if (modal) modal.remove();
// stop further preview logic
return;
} else if (/\.(mp4|mkv|webm|mov|ogv)$/i.test(fileName)) {
const video = document.createElement("video");
video.src = fileUrl;
video.controls = true;