Improve PDF preview and input focus behaviors
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# 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 form’s 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
|
## Changes 4/28/2025
|
||||||
|
|
||||||
**Added**
|
**Added**
|
||||||
@@ -28,7 +38,7 @@
|
|||||||
|
|
||||||
- OpenAPI annotations for both endpoints updated to require `expirationValue` + `expirationUnit` (enum: seconds, minutes, hours, days)
|
- 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
|
- **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
|
||||||
|
|||||||
@@ -182,7 +182,7 @@
|
|||||||
<form id="authForm" method="post">
|
<form id="authForm" method="post">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="loginUsername" data-i18n-key="user">User:</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="loginPassword" data-i18n-key="password">Password:</label>
|
<label for="loginPassword" data-i18n-key="password">Password:</label>
|
||||||
@@ -442,18 +442,30 @@
|
|||||||
<div id="addUserModal" class="modal">
|
<div id="addUserModal" class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<h3 data-i18n-key="create_new_user_title">Create New User</h3>
|
<h3 data-i18n-key="create_new_user_title">Create New User</h3>
|
||||||
|
<!-- 1) Add a form around these fields -->
|
||||||
|
<form id="addUserForm">
|
||||||
<label for="newUsername" data-i18n-key="username">Username:</label>
|
<label for="newUsername" data-i18n-key="username">Username:</label>
|
||||||
<input type="text" id="newUsername" class="form-control" />
|
<input type="text" id="newUsername" class="form-control" required />
|
||||||
|
|
||||||
<label for="addUserPassword" data-i18n-key="password">Password:</label>
|
<label for="addUserPassword" data-i18n-key="password">Password:</label>
|
||||||
<input type="password" id="addUserPassword" class="form-control" />
|
<input type="password" id="addUserPassword" class="form-control" required />
|
||||||
|
|
||||||
<div id="adminCheckboxContainer">
|
<div id="adminCheckboxContainer">
|
||||||
<input type="checkbox" id="isAdmin" />
|
<input type="checkbox" id="isAdmin" />
|
||||||
<label for="isAdmin" data-i18n-key="grant_admin">Grant Admin Access</label>
|
<label for="isAdmin" data-i18n-key="grant_admin">Grant Admin Access</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<button id="cancelUserBtn" class="btn btn-secondary" data-i18n-key="cancel">Cancel</button>
|
<!-- Cancel stays type="button" -->
|
||||||
<button id="saveUserBtn" class="btn btn-primary" data-i18n-key="save_user">Save User</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>
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="removeUserModal" class="modal">
|
<div id="removeUserModal" class="modal">
|
||||||
|
|||||||
@@ -125,10 +125,17 @@ function updateItemsPerPageSelect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }) {
|
function updateLoginOptionsUI({ disableFormLogin, disableBasicAuth, disableOIDCLogin }) {
|
||||||
const authForm = document.getElementById("authForm");
|
const authForm = document.getElementById("authForm");
|
||||||
|
if
|
||||||
if (authForm) authForm.style.display = disableFormLogin ? "none" : "block";
|
(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']");
|
const basicAuthLink = document.querySelector("a[href='/api/auth/login_basic.php']");
|
||||||
if (basicAuthLink) basicAuthLink.style.display = disableBasicAuth ? "none" : "inline-block";
|
if (basicAuthLink) basicAuthLink.style.display = disableBasicAuth ? "none" : "inline-block";
|
||||||
const oidcLoginBtn = document.getElementById("oidcLoginBtn");
|
const oidcLoginBtn = document.getElementById("oidcLoginBtn");
|
||||||
@@ -187,7 +194,7 @@ function updateAuthenticatedUI(data) {
|
|||||||
toggleVisibility("mainOperations", true);
|
toggleVisibility("mainOperations", true);
|
||||||
toggleVisibility("uploadFileForm", true);
|
toggleVisibility("uploadFileForm", true);
|
||||||
toggleVisibility("fileListContainer", true);
|
toggleVisibility("fileListContainer", true);
|
||||||
attachEnterKeyListener("addUserModal", "saveUserBtn");
|
//attachEnterKeyListener("addUserModal", "saveUserBtn");
|
||||||
attachEnterKeyListener("removeUserModal", "deleteUserBtn");
|
attachEnterKeyListener("removeUserModal", "deleteUserBtn");
|
||||||
attachEnterKeyListener("changePasswordModal", "saveNewPasswordBtn");
|
attachEnterKeyListener("changePasswordModal", "saveNewPasswordBtn");
|
||||||
document.querySelector(".header-buttons").style.visibility = "visible";
|
document.querySelector(".header-buttons").style.visibility = "visible";
|
||||||
@@ -443,23 +450,33 @@ function initAuth() {
|
|||||||
toggleVisibility("addUserModal", true);
|
toggleVisibility("addUserModal", true);
|
||||||
document.getElementById("newUsername").focus();
|
document.getElementById("newUsername").focus();
|
||||||
});
|
});
|
||||||
document.getElementById("saveUserBtn").addEventListener("click", function () {
|
|
||||||
|
// 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 newUsername = document.getElementById("newUsername").value.trim();
|
||||||
const newPassword = document.getElementById("addUserPassword").value.trim();
|
const newPassword = document.getElementById("addUserPassword").value.trim();
|
||||||
const isAdmin = document.getElementById("isAdmin").checked;
|
const isAdmin = document.getElementById("isAdmin").checked;
|
||||||
|
|
||||||
if (!newUsername || !newPassword) {
|
if (!newUsername || !newPassword) {
|
||||||
showToast("Username and password are required!");
|
showToast("Username and password are required!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = "/api/addUser.php";
|
let url = "/api/addUser.php";
|
||||||
if (window.setupMode) url += "?setup=1";
|
if (window.setupMode) url += "?setup=1";
|
||||||
|
|
||||||
fetchWithCsrf(url, {
|
fetchWithCsrf(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
|
body: JSON.stringify({ username: newUsername, password: newPassword, isAdmin })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
showToast("User added successfully!");
|
showToast("User added successfully!");
|
||||||
@@ -469,8 +486,10 @@ function initAuth() {
|
|||||||
showToast("Error: " + (data.error || "Could not add user"));
|
showToast("Error: " + (data.error || "Could not add user"));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => { });
|
.catch(() => {
|
||||||
|
showToast("Error: Could not add user");
|
||||||
});
|
});
|
||||||
|
});
|
||||||
document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal);
|
document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal);
|
||||||
|
|
||||||
document.getElementById("removeUserBtn").addEventListener("click", function () {
|
document.getElementById("removeUserBtn").addEventListener("click", function () {
|
||||||
|
|||||||
@@ -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.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>`;
|
const adminTitle = `${t("admin_panel")} <small style="font-size: 12px; color: gray;">${version}</small>`;
|
||||||
|
|
||||||
let lastLoginData = null;
|
let lastLoginData = null;
|
||||||
|
|||||||
@@ -417,14 +417,19 @@ export function previewFile(fileUrl, fileName) {
|
|||||||
} else {
|
} else {
|
||||||
// Handle non-image file previews.
|
// Handle non-image file previews.
|
||||||
if (extension === "pdf") {
|
if (extension === "pdf") {
|
||||||
const embed = document.createElement("embed");
|
// build a cache‐busted URL
|
||||||
const separator = fileUrl.indexOf('?') === -1 ? '?' : '&';
|
const separator = fileUrl.includes('?') ? '&' : '?';
|
||||||
embed.src = fileUrl + separator + 't=' + new Date().getTime();
|
const urlWithTs = fileUrl + separator + 't=' + Date.now();
|
||||||
embed.type = "application/pdf";
|
|
||||||
embed.style.width = "80vw";
|
// open in a new tab (avoids CSP frame-ancestors)
|
||||||
embed.style.height = "80vh";
|
window.open(urlWithTs, "_blank");
|
||||||
embed.style.border = "none";
|
|
||||||
container.appendChild(embed);
|
// 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)) {
|
} else if (/\.(mp4|mkv|webm|mov|ogv)$/i.test(fileName)) {
|
||||||
const video = document.createElement("video");
|
const video = document.createElement("video");
|
||||||
video.src = fileUrl;
|
video.src = fileUrl;
|
||||||
|
|||||||
Reference in New Issue
Block a user