extends the functionality of oauth in Stirling PDF 2.
This commit is contained in:
@@ -1,300 +1,277 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-9" id="bg-card">
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-9">
|
||||
|
||||
<!-- User Settings Title -->
|
||||
<h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2>
|
||||
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
|
||||
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger">
|
||||
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span>
|
||||
<!-- User Settings Title -->
|
||||
<h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2>
|
||||
<th:block th:if="${messageType}">
|
||||
<div class="alert alert-danger">
|
||||
<span th:text="#{${messageType}}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
|
||||
<span th:text="#{userNotFoundMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
|
||||
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
|
||||
<span th:text="#{usernameExistsMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'invalidUsername'}" class="alert alert-danger">
|
||||
<span th:text="#{invalidUsernameMessage}">Default message if not found</span>
|
||||
</div>
|
||||
</th:block>
|
||||
<!-- At the top of the user settings -->
|
||||
<h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3>
|
||||
<th:block th:if="${error}">
|
||||
</th:block>
|
||||
<!-- At the top of the user settings -->
|
||||
<h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3>
|
||||
<th:block th:if="${error}">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<span th:text="${error}">Error Message</span>
|
||||
</div>
|
||||
</th:block>
|
||||
<!-- Change Username Form -->
|
||||
<h4 th:text="#{account.changeUsername}">Change Username?</h4>
|
||||
<form th:if="${!oAuth2Login}" id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-username" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="newUsername" th:text="#{account.newUsername}">Change Username</label>
|
||||
<input type="text" class="form-control" name="newUsername" id="newUsername"
|
||||
th:placeholder="#{account.newUsername}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="currentPassword" th:text="#{password}">Password</label>
|
||||
<input type="password" class="form-control" name="currentPassword" id="currentPassword"
|
||||
th:placeholder="#{password}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change
|
||||
Username</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Change Password Form -->
|
||||
<h4 th:if="${!oAuth2Login}" th:text="#{account.changePassword}">Change Password?</h4>
|
||||
<form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-password" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
|
||||
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword"
|
||||
th:placeholder="#{account.oldPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newPassword" th:text="#{account.newPassword}">New Password</label>
|
||||
<input type="password" class="form-control" name="newPassword" id="newPassword"
|
||||
th:placeholder="#{account.newPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label>
|
||||
<input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword"
|
||||
th:placeholder="#{account.confirmNewPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change
|
||||
Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</th:block>
|
||||
<!-- Change Username Form -->
|
||||
<th:block th:if="${!oAuth2Login}">
|
||||
<h4 th:text="#{account.changeUsername}">Change Username?</h4>
|
||||
<form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-username" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="newUsername" th:text="#{account.newUsername}">Change Username</label>
|
||||
<input type="text" class="form-control" name="newUsername" id="newUsername" th:placeholder="#{account.newUsername}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="currentPassword" th:text="#{password}">Password</label>
|
||||
<input type="password" class="form-control" name="currentPassword" id="currentPassword" th:placeholder="#{password}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change Username</button>
|
||||
</div>
|
||||
</form>
|
||||
</th:block>
|
||||
|
||||
<!-- Change Password Form -->
|
||||
<th:block th:if="${!oAuth2Login}">
|
||||
<h4 th:text="#{account.changePassword}">Change Password?</h4>
|
||||
<form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-password" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
|
||||
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" th:placeholder="#{account.oldPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newPassword" th:text="#{account.newPassword}">New Password</label>
|
||||
<input type="password" class="form-control" name="newPassword" id="newPassword" th:placeholder="#{account.newPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label>
|
||||
<input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword" th:placeholder="#{account.confirmNewPassword}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</th:block>
|
||||
|
||||
<!-- API Key Form -->
|
||||
<h4 th:text="#{account.yourApiKey}">API Key</h4>
|
||||
<div class="card mt-4 mb-4">
|
||||
<div class="card-header" th:text="#{account.yourApiKey}"></div>
|
||||
<div class="card-body">
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}"
|
||||
readonly>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" id="copyBtn" type="button" onclick="copyToClipboard()">
|
||||
<span class="material-symbols-rounded">
|
||||
<div class="card mt-4 mb-4">
|
||||
<div class="card-header" th:text="#{account.yourApiKey}"></div>
|
||||
<div class="card-body">
|
||||
<div class="input-group mb-3">
|
||||
<input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" readonly>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" id="copyBtn" type="button" onclick="copyToClipboard()">
|
||||
<span class="material-symbols-rounded">
|
||||
content_copy
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="showBtn" type="button" onclick="showApiKey()">
|
||||
<span class="material-symbols-rounded" id="eyeIcon">
|
||||
visibility
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()">
|
||||
<span class="material-symbols-rounded">
|
||||
refresh
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="showBtn" type="button" onclick="showApiKey()">
|
||||
<span class="material-symbols-rounded" id="eyeIcon">
|
||||
visibility
|
||||
</span>
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()">
|
||||
<span class="material-symbols-rounded">
|
||||
refresh
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyToClipboard() {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
apiKeyElement.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
function showApiKey() {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
const copyBtn = document.getElementById("copyBtn");
|
||||
const eyeIcon = document.getElementById("eyeIcon");
|
||||
if (apiKeyElement.type === "password") {
|
||||
apiKeyElement.type = "text";
|
||||
eyeIcon.textContent = "visibility_off";
|
||||
copyBtn.disabled = false; // Enable copy button when API key is visible
|
||||
} else {
|
||||
apiKeyElement.type = "password";
|
||||
eyeIcon.textContent = "visibility";
|
||||
copyBtn.disabled = true; // Disable copy button when API key is hidden
|
||||
<script>
|
||||
function copyToClipboard() {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
apiKeyElement.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async function () {
|
||||
try {
|
||||
let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' });
|
||||
if (response.status === 200) {
|
||||
let apiKey = await response.text();
|
||||
manageUIState(apiKey);
|
||||
function showApiKey() {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
const copyBtn = document.getElementById("copyBtn");
|
||||
const eyeIcon = document.getElementById("eyeIcon");
|
||||
if (apiKeyElement.type === "password") {
|
||||
apiKeyElement.type = "text";
|
||||
eyeIcon.textContent = "visibility_off";
|
||||
copyBtn.disabled = false; // Enable copy button when API key is visible
|
||||
} else {
|
||||
manageUIState(null);
|
||||
apiKeyElement.type = "password";
|
||||
eyeIcon.textContent = "visibility";
|
||||
copyBtn.disabled = true; // Disable copy button when API key is hidden
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('There was an error:', error);
|
||||
}
|
||||
});
|
||||
|
||||
async function refreshApiKey() {
|
||||
try {
|
||||
let response = await fetch('/api/v1/user/update-api-key', { method: 'POST' });
|
||||
if (response.status === 200) {
|
||||
let apiKey = await response.text();
|
||||
manageUIState(apiKey);
|
||||
document.getElementById("apiKey").type = 'text';
|
||||
document.getElementById("copyBtn").disabled = false;
|
||||
} else {
|
||||
alert('Error refreshing API key.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('There was an error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function manageUIState(apiKey) {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
const showBtn = document.getElementById("showBtn");
|
||||
const copyBtn = document.getElementById("copyBtn");
|
||||
|
||||
if (apiKey && apiKey.trim().length > 0) {
|
||||
apiKeyElement.value = apiKey;
|
||||
showBtn.disabled = false;
|
||||
copyBtn.disabled = true;
|
||||
} else {
|
||||
apiKeyElement.value = "";
|
||||
showBtn.disabled = true;
|
||||
copyBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const form = document.querySelector('form[action="api/v1/user/change-password"]');
|
||||
|
||||
form.addEventListener('submit', function (event) {
|
||||
const newPassword = document.getElementById('newPassword').value;
|
||||
const confirmNewPassword = document.getElementById('confirmNewPassword').value;
|
||||
|
||||
if (newPassword !== confirmNewPassword) {
|
||||
alert('New Password and Confirm New Password must match.');
|
||||
event.preventDefault(); // Prevent form submission
|
||||
document.addEventListener("DOMContentLoaded", async function() {
|
||||
try {
|
||||
let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' });
|
||||
if (response.status === 200) {
|
||||
let apiKey = await response.text();
|
||||
manageUIState(apiKey);
|
||||
} else {
|
||||
manageUIState(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('There was an error:', error);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4>
|
||||
<div id="bg-card" class="container mt-4">
|
||||
<h3 th:text="#{account.settingsCompare}">Settings Comparison:</h3>
|
||||
<table id="settingsTable" class="table table-bordered table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th th:text="#{account.property}">Property</th>
|
||||
<th th:text="#{account.accountSettings}">Account Setting</th>
|
||||
<th th:text="#{account.webBrowserSettings}">Web Browser Setting</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- This will be dynamically populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
async function refreshApiKey() {
|
||||
try {
|
||||
let response = await fetch('/api/v1/user/update-api-key', { method: 'POST' });
|
||||
if (response.status === 200) {
|
||||
let apiKey = await response.text();
|
||||
manageUIState(apiKey);
|
||||
document.getElementById("apiKey").type = 'text';
|
||||
document.getElementById("copyBtn").disabled = false;
|
||||
} else {
|
||||
alert('Error refreshing API key.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('There was an error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
<div class="buttons-container mt-3 text-center">
|
||||
<button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync
|
||||
Account -> Browser</button>
|
||||
<button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync
|
||||
Account <- Browser</button>
|
||||
function manageUIState(apiKey) {
|
||||
const apiKeyElement = document.getElementById("apiKey");
|
||||
const showBtn = document.getElementById("showBtn");
|
||||
const copyBtn = document.getElementById("copyBtn");
|
||||
|
||||
if (apiKey && apiKey.trim().length > 0) {
|
||||
apiKeyElement.value = apiKey;
|
||||
showBtn.disabled = false;
|
||||
copyBtn.disabled = true;
|
||||
} else {
|
||||
apiKeyElement.value = "";
|
||||
showBtn.disabled = true;
|
||||
copyBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const form = document.querySelector('form[action="api/v1/user/change-password"]');
|
||||
|
||||
form.addEventListener('submit', function(event) {
|
||||
const newPassword = document.getElementById('newPassword').value;
|
||||
const confirmNewPassword = document.getElementById('confirmNewPassword').value;
|
||||
|
||||
if (newPassword !== confirmNewPassword) {
|
||||
alert('New Password and Confirm New Password must match.');
|
||||
event.preventDefault(); // Prevent form submission
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4>
|
||||
<div id="bg-card" class="container mt-4">
|
||||
<h3 th:text="#{account.settingsCompare}">Settings Comparison:</h3>
|
||||
<table id="settingsTable" class="table table-bordered table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th th:text="#{account.property}">Property</th>
|
||||
<th th:text="#{account.accountSettings}">Account Setting</th>
|
||||
<th th:text="#{account.webBrowserSettings}">Web Browser Setting</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- This will be dynamically populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="buttons-container mt-3 text-center">
|
||||
<button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync Account -> Browser</button>
|
||||
<button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync Account <- Browser</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const settingsTableBody = document.querySelector("#settingsTable tbody");
|
||||
<script th:inline="javascript">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const settingsTableBody = document.querySelector("#settingsTable tbody");
|
||||
|
||||
/*<![CDATA[*/
|
||||
var accountSettingsString = /*[[${settings}]]*/ {};
|
||||
/*]]>*/
|
||||
var accountSettings = JSON.parse(accountSettingsString);
|
||||
/*<![CDATA[*/
|
||||
var accountSettingsString = /*[[${settings}]]*/ {};
|
||||
/*]]>*/
|
||||
var accountSettings = JSON.parse(accountSettingsString);
|
||||
|
||||
let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]);
|
||||
let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]);
|
||||
|
||||
allKeys.forEach(key => {
|
||||
if (key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys
|
||||
allKeys.forEach(key => {
|
||||
if(key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys
|
||||
|
||||
const accountValue = accountSettings[key] || '-';
|
||||
const browserValue = localStorage.getItem(key) || '-';
|
||||
const accountValue = accountSettings[key] || '-';
|
||||
const browserValue = localStorage.getItem(key) || '-';
|
||||
|
||||
const row = settingsTableBody.insertRow();
|
||||
const propertyCell = row.insertCell(0);
|
||||
const accountCell = row.insertCell(1);
|
||||
const browserCell = row.insertCell(2);
|
||||
const row = settingsTableBody.insertRow();
|
||||
const propertyCell = row.insertCell(0);
|
||||
const accountCell = row.insertCell(1);
|
||||
const browserCell = row.insertCell(2);
|
||||
|
||||
propertyCell.textContent = key;
|
||||
accountCell.textContent = accountValue;
|
||||
browserCell.textContent = browserValue;
|
||||
});
|
||||
propertyCell.textContent = key;
|
||||
accountCell.textContent = accountValue;
|
||||
browserCell.textContent = browserValue;
|
||||
});
|
||||
|
||||
document.getElementById('syncToBrowser').addEventListener('click', function () {
|
||||
// First, clear the local storage
|
||||
localStorage.clear();
|
||||
document.getElementById('syncToBrowser').addEventListener('click', function() {
|
||||
// First, clear the local storage
|
||||
localStorage.clear();
|
||||
|
||||
// Then, set the account settings to local storage
|
||||
for (let key in accountSettings) {
|
||||
if (key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys
|
||||
localStorage.setItem(key, accountSettings[key]);
|
||||
// Then, set the account settings to local storage
|
||||
for (let key in accountSettings) {
|
||||
if(key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys
|
||||
localStorage.setItem(key, accountSettings[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
location.reload(); // Refresh the page after sync
|
||||
});
|
||||
location.reload(); // Refresh the page after sync
|
||||
});
|
||||
|
||||
document.getElementById('syncToAccount').addEventListener('click', function () {
|
||||
let form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL
|
||||
document.getElementById('syncToAccount').addEventListener('click', function() {
|
||||
let form = document.createElement("form");
|
||||
form.method = "POST";
|
||||
form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL
|
||||
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys
|
||||
let hiddenField = document.createElement("input");
|
||||
hiddenField.type = "hidden";
|
||||
hiddenField.name = key;
|
||||
hiddenField.value = localStorage.getItem(key);
|
||||
form.appendChild(hiddenField);
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if(key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys
|
||||
let hiddenField = document.createElement("input");
|
||||
hiddenField.type = "hidden";
|
||||
hiddenField.name = key;
|
||||
hiddenField.value = localStorage.getItem(key);
|
||||
form.appendChild(hiddenField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
<div class="mb-3 mt-4 text-center">
|
||||
<a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a>
|
||||
<a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button"
|
||||
th:text="#{account.adminSettings}" target="_blank">Admin Settings</a>
|
||||
</script>
|
||||
<div class="mb-3 mt-4 text-center">
|
||||
<a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a>
|
||||
<a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button" th:text="#{account.adminSettings}" target="_blank">Admin Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
<!-- User Settings Title -->
|
||||
<h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2>
|
||||
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'deleteCurrentUser' or param.messageType[0] == 'deleteUsernameExists')}" class="alert alert-danger">
|
||||
<span th:if="${param.messageType[0] == 'deleteCurrentUser'}" th:text="#{deleteCurrentUserMessage}">Cannot delete currently logged in user.</span>
|
||||
<span th:if="${param.messageType[0] == 'deleteUsernameExists'}" th:text="#{deleteUsernameExistsMessage}">The username does not exist and cannot be deleted.</span>
|
||||
<div th:if="${deleteMessage}" class="alert alert-danger">
|
||||
<span th:text="#{${deleteMessage}}">Message</span>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
@@ -26,7 +25,7 @@
|
||||
<th th:text="#{username}">Username</th>
|
||||
<th th:text="#{adminUserSettings.roles}">Roles</th>
|
||||
<th th:text="#{adminUserSettings.actions}">Actions</th>
|
||||
<th th:text="#{adminUserSettings.authenticated}">Authentication type</th>
|
||||
<th th:text="#{adminUserSettings.authenticated}">Authenticated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -44,15 +43,15 @@
|
||||
</table>
|
||||
|
||||
<h2 th:text="#{adminUserSettings.addUser}">Add New User</h2>
|
||||
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'usernameExists' or param.messageType[0] == 'invalidUsername')}" class="alert alert-danger">
|
||||
<span th:if="${param.messageType[0] == 'usernameExists'}" th:text="#{usernameExistsMessage}">Default message if not found</span>
|
||||
<span th:if="${param.messageType[0] == 'invalidUsername'}" th:text="#{invalidUsernameMessage}">Default message if not found</span>
|
||||
<div th:if="${addMessage}" class="alert alert-danger">
|
||||
<span th:text="#{${addMessage}}">Default message if not found</span>
|
||||
</div>
|
||||
<button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{adminUserSettings.usernameInfo}" th:text="#{help}">Help</button>
|
||||
<form action="/api/v1/user/admin/saveUser" method="post">
|
||||
<form id="formsaveuser" action="/api/v1/user/admin/saveUser" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="username" th:text="#{username}">Username</label>
|
||||
<input type="text" class="form-control" name="username" id="username" th:title="#{adminUserSettings.usernameInfo}" required>
|
||||
<span id="usernameError" style="display: none;" th:text="#{invalidUsernameMessage}">Invalid username!</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" th:text="#{password}">Password</label>
|
||||
@@ -76,9 +75,8 @@
|
||||
<hr />
|
||||
<h2 th:text="#{adminUserSettings.changeUserRole}">Change User's Role</h2>
|
||||
<button class="btn btn-outline-info" data-toggle="tooltip" data-placement="auto" th:title="#{downgradeCurrentUserLongMessage}" th:text="#{help}">Help</button>
|
||||
<div th:if="${param.messageType != null and param.messageType.size() > 0 and (param.messageType[0] == 'userNotFound' or param.messageType[0] == 'downgradeCurrentUser')}" class="alert alert-danger">
|
||||
<span th:if="${param.messageType[0] == 'userNotFound'}" th:text="#{userNotFoundMessage}">Username not found</span>
|
||||
<span th:if="${param.messageType[0] == 'downgradeCurrentUser'}" th:text="#{downgradeCurrentUserMessage}">Cannot downgrade current user's role</span>
|
||||
<div th:if="${changeMessage}" class="alert alert-danger">
|
||||
<span th:text="#{${changeMessage}}">Default message if not found</span>
|
||||
</div>
|
||||
<form action="/api/v1/user/admin/changeRole" method="post">
|
||||
<div class="mb-3">
|
||||
@@ -104,9 +102,55 @@
|
||||
</div>
|
||||
</div>
|
||||
<script th:inline="javascript">
|
||||
jQuery.validator.addMethod("usernamePattern", function(value, element) {
|
||||
return this.optional(element) || /^[a-zA-Z0-9][a-zA-Z0-9@._+-]*[a-zA-Z0-9]$|^(?=.{1,64}@)[A-Za-z0-9]+(\.[A-Za-z0-9_+.-]+)*@[^-][A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(\.[A-Za-z]{2,})$/.test(value);
|
||||
}, /*[[#{invalidUsernameMessage}]]*/ "Invalid username format");
|
||||
$(document).ready(function() {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
$('#formsaveuser').validate({
|
||||
rules: {
|
||||
username: {
|
||||
required: true,
|
||||
usernamePattern: true
|
||||
},
|
||||
password: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
username: {
|
||||
usernamePattern: /*[[#{invalidUsernameMessage}]]*/ "Invalid username format"
|
||||
},
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
if (element.attr("name") === "username") {
|
||||
$("#usernameError").text(error.text()).show();
|
||||
} else {
|
||||
error.insertAfter(element);
|
||||
}
|
||||
},
|
||||
success: function(label, element) {
|
||||
if ($(element).attr("name") === "username") {
|
||||
$("#usernameError").hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#username').on('input', function() {
|
||||
var usernameInput = $(this);
|
||||
var isValid = usernameInput[0].checkValidity();
|
||||
var errorSpan = $('#usernameError');
|
||||
|
||||
if (isValid) {
|
||||
usernameInput.removeClass('invalid').addClass('valid');
|
||||
errorSpan.hide();
|
||||
} else {
|
||||
usernameInput.removeClass('valid').addClass('invalid');
|
||||
errorSpan.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
|
||||
@@ -17,18 +17,9 @@
|
||||
<!-- User Settings Title -->
|
||||
<h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2>
|
||||
<hr>
|
||||
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
|
||||
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger">
|
||||
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'userNotFound'}" class="alert alert-danger">
|
||||
<span th:text="#{userNotFoundMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'incorrectPassword'}" class="alert alert-danger">
|
||||
<span th:text="#{incorrectPasswordMessage}">Default message if not found</span>
|
||||
</div>
|
||||
<div th:if="${param.messageType[0] == 'usernameExists'}" class="alert alert-danger">
|
||||
<span th:text="#{usernameExistsMessage}">Default message if not found</span>
|
||||
<th:block th:if="${messageType}">
|
||||
<div class="alert alert-danger">
|
||||
<span th:text="#{${messageType}}">Default message if not found</span>
|
||||
</div>
|
||||
</th:block>
|
||||
<!-- At the top of the user settings -->
|
||||
|
||||
@@ -1,174 +1,170 @@
|
||||
<th:block th:fragment="head">
|
||||
<!-- Title -->
|
||||
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
|
||||
<!-- Title -->
|
||||
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
|
||||
|
||||
<!-- Metadata -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Metadata -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=2">
|
||||
<link rel="manifest" href="/site.webmanifest?v=2">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=2" color="#ca2b2a">
|
||||
<link rel="shortcut icon" href="/favicon.ico?v=2">
|
||||
<meta name="apple-mobile-web-app-title" content="Stirling PDF">
|
||||
<meta name="application-name" content="Stirling PDF">
|
||||
<meta name="msapplication-TileColor" content="#00aba9">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<!-- Icons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png?v=2">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png?v=2">
|
||||
<link rel="manifest" href="site.webmanifest?v=2">
|
||||
<link rel="mask-icon" href="safari-pinned-tab.svg?v=2" color="#ca2b2a">
|
||||
<link rel="shortcut icon" href="favicon.ico?v=2">
|
||||
<meta name="apple-mobile-web-app-title" content="Stirling PDF">
|
||||
<meta name="application-name" content="Stirling PDF">
|
||||
<meta name="msapplication-TileColor" content="#00aba9">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="js/thirdParty/jquery.min.js"></script>
|
||||
<script src="js/thirdParty/jszip.min.js"></script>
|
||||
<!-- jQuery -->
|
||||
<script src="js/thirdParty/jquery.min.js"></script>
|
||||
<script src="js/thirdParty/jquery.validate.min.js"></script>
|
||||
<script src="js/thirdParty/jszip.min.js"></script>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<script src="js/thirdParty/popper.min.js"></script>
|
||||
<script src="js/thirdParty/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<!-- Bootstrap -->
|
||||
<script src="js/thirdParty/popper.min.js"></script>
|
||||
<script src="js/thirdParty/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="css/bootstrap-icons.min.css">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="css/bootstrap-icons.min.css">
|
||||
|
||||
<!-- PDF.js -->
|
||||
<script th:src="@{pdfjs/pdf.js}"></script>
|
||||
<!-- PDF.js -->
|
||||
<script th:src="@{pdfjs/pdf.js}"></script>
|
||||
|
||||
<!-- PDF-Lib -->
|
||||
<script src="js/thirdParty/pdf-lib.min.js"></script>
|
||||
<!-- PDF-Lib -->
|
||||
<script src="js/thirdParty/pdf-lib.min.js"></script>
|
||||
|
||||
<!-- Custom -->
|
||||
<link rel="stylesheet" href="css/general.css">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.css}">
|
||||
<link rel="stylesheet" th:href="@{css/theme/componentes.css}">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.light.css}" id="light-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.dark.css}" id="dark-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled>
|
||||
<link rel="stylesheet" href="css/tab-container.css">
|
||||
<link rel="stylesheet" href="css/navbar.css">
|
||||
<!-- Custom -->
|
||||
<link rel="stylesheet" href="css/general.css">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.css}">
|
||||
<link rel="stylesheet" th:href="@{css/theme/componentes.css}">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.light.css}" id="light-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{css/theme/theme.dark.css}" id="dark-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled>
|
||||
<link rel="stylesheet" href="css/tab-container.css">
|
||||
<link rel="stylesheet" href="css/navbar.css">
|
||||
|
||||
<link rel="stylesheet" th:href="@{/css/error.css}" th:if="${error}">
|
||||
<link rel="stylesheet" th:href="@{/css/error.css}" th:if="${error}">
|
||||
|
||||
<link rel="stylesheet" href="css/home.css" th:if="${currentPage == 'home'}">
|
||||
<link rel="stylesheet" href="css/account.css" th:if="${currentPage == 'account'}">
|
||||
<link rel="stylesheet" href="css/licenses.css" th:if="${currentPage == 'licenses'}">
|
||||
<link rel="stylesheet" href="css/multi-tool.css" th:if="${currentPage == 'multi-tool'}">
|
||||
<link rel="stylesheet" href="css/rotate-pdf.css" th:if="${currentPage == 'rotate-pdf'}">
|
||||
<link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}">
|
||||
<link rel="stylesheet" href="css/fileSelect.css">
|
||||
<link rel="stylesheet" href="css/footer.css">
|
||||
<script src="js/thirdParty/fontfaceobserver.standalone.js"></script>
|
||||
<link rel="stylesheet" href="css/home.css" th:if="${currentPage == 'home'}">
|
||||
<link rel="stylesheet" href="css/account.css" th:if="${currentPage == 'account'}">
|
||||
<link rel="stylesheet" href="css/licenses.css" th:if="${currentPage == 'licenses'}">
|
||||
<link rel="stylesheet" href="css/multi-tool.css" th:if="${currentPage == 'multi-tool'}">
|
||||
<link rel="stylesheet" href="css/rotate-pdf.css" th:if="${currentPage == 'rotate-pdf'}">
|
||||
<link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}">
|
||||
<link rel="stylesheet" href="css/fileSelect.css">
|
||||
<link rel="stylesheet" href="css/footer.css">
|
||||
<script src="js/thirdParty/fontfaceobserver.standalone.js"></script>
|
||||
|
||||
<!-- Google MD Icons -->
|
||||
<link rel="stylesheet" href="css/theme/font.css">
|
||||
<!-- Google MD Icons -->
|
||||
<link rel="stylesheet" href="css/theme/font.css">
|
||||
|
||||
<!-- Help Modal -->
|
||||
<link rel="stylesheet" href="css/errorBanner.css">
|
||||
|
||||
<script src="js/cacheFormInputs.js"></script>
|
||||
<script src="js/tab-container.js"></script>
|
||||
<script src="js/darkmode.js"></script>
|
||||
</th:block>
|
||||
<!-- Help Modal -->
|
||||
<link rel="stylesheet" href="css/errorBanner.css">
|
||||
|
||||
<script src="js/cacheFormInputs.js"></script>
|
||||
<script src="js/tab-container.js"></script>
|
||||
<script src="js/darkmode.js"></script>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="game">
|
||||
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
|
||||
<script th:inline="javascript">
|
||||
console.log("loaded game");
|
||||
$(document).ready(function () {
|
||||
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
|
||||
<script th:inline="javascript">
|
||||
console.log("loaded game");
|
||||
$(document).ready(function() {
|
||||
|
||||
// Find the file input within the form
|
||||
var fileInput = $('input[type="file"]');
|
||||
// Find the file input within the form
|
||||
var fileInput = $('input[type="file"]');
|
||||
|
||||
// Find the closest enclosing form of the file input
|
||||
var form = fileInput.closest('form');
|
||||
|
||||
// Find the submit button within the form
|
||||
var submitButton = form.find('button[type="submit"], input[type="submit"]');
|
||||
|
||||
const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
|
||||
const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
|
||||
window.downloadCompleteText = downloadCompleteText;
|
||||
// Create the 'show-game-btn' button
|
||||
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button><br><br>');
|
||||
|
||||
// Insert the 'show-game-btn' just above the submit button
|
||||
submitButton.before(gameButton);
|
||||
|
||||
// Find the closest enclosing form of the file input
|
||||
var form = fileInput.closest('form');
|
||||
|
||||
// Find the submit button within the form
|
||||
var submitButton = form.find('button[type="submit"], input[type="submit"]');
|
||||
|
||||
const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
|
||||
const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
|
||||
window.downloadCompleteText = downloadCompleteText;
|
||||
// Create the 'show-game-btn' button
|
||||
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button><br><br>');
|
||||
|
||||
// Insert the 'show-game-btn' just above the submit button
|
||||
submitButton.before(gameButton);
|
||||
|
||||
function loadGameScript(callback) {
|
||||
console.log('loadGameScript called');
|
||||
const script = document.createElement('script');
|
||||
script.src = 'js/game.js';
|
||||
script.onload = callback;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
let gameScriptLoaded = false;
|
||||
const gameDialog = document.getElementById('game-container-wrapper');
|
||||
$('#show-game-btn').on('click', function () {
|
||||
console.log('Show game button clicked');
|
||||
if (!gameScriptLoaded) {
|
||||
console.log('Show game button load');
|
||||
loadGameScript(function () {
|
||||
console.log('Game script loaded');
|
||||
window.initializeGame();
|
||||
gameScriptLoaded = true;
|
||||
});
|
||||
} else {
|
||||
window.resetGame();
|
||||
}
|
||||
gameDialog.showModal();
|
||||
});
|
||||
gameDialog.addEventListener("click", e => {
|
||||
const dialogDimensions = gameDialog.getBoundingClientRect()
|
||||
if (
|
||||
e.clientX < dialogDimensions.left ||
|
||||
e.clientX > dialogDimensions.right ||
|
||||
e.clientY < dialogDimensions.top ||
|
||||
e.clientY > dialogDimensions.bottom
|
||||
) {
|
||||
gameDialog.close();
|
||||
function loadGameScript(callback) {
|
||||
console.log('loadGameScript called');
|
||||
const script = document.createElement('script');
|
||||
script.src = 'js/game.js';
|
||||
script.onload = callback;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
let gameScriptLoaded = false;
|
||||
const gameDialog = document.getElementById('game-container-wrapper');
|
||||
$('#show-game-btn').on('click', function() {
|
||||
console.log('Show game button clicked');
|
||||
if (!gameScriptLoaded) {
|
||||
console.log('Show game button load');
|
||||
loadGameScript(function() {
|
||||
console.log('Game script loaded');
|
||||
window.initializeGame();
|
||||
gameScriptLoaded = true;
|
||||
});
|
||||
} else {
|
||||
window.resetGame();
|
||||
}
|
||||
gameDialog.showModal();
|
||||
});
|
||||
gameDialog.addEventListener("click", e => {
|
||||
const dialogDimensions = gameDialog.getBoundingClientRect()
|
||||
if (
|
||||
e.clientX < dialogDimensions.left ||
|
||||
e.clientX > dialogDimensions.right ||
|
||||
e.clientY < dialogDimensions.top ||
|
||||
e.clientY > dialogDimensions.bottom
|
||||
) {
|
||||
gameDialog.close();
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<div id="game-container">
|
||||
<div id="lives">Lives: 3</div>
|
||||
<div id="score">Score: 0</div>
|
||||
<div id="high-score">High Score: 0</div>
|
||||
<div id="level">Level: 1</div>
|
||||
<img src="favicon.svg" class="player" id="player" alt="favicon">
|
||||
</div>
|
||||
<link rel="stylesheet" href="css/game.css">
|
||||
</dialog>
|
||||
</script>
|
||||
<div id="game-container">
|
||||
<div id="lives">Lives: 3</div>
|
||||
<div id="score">Score: 0</div>
|
||||
<div id="high-score">High Score: 0</div>
|
||||
<div id="level">Level: 1</div>
|
||||
<img src="favicon.svg" class="player" id="player" alt="favicon">
|
||||
</div>
|
||||
<link rel="stylesheet" href="css/game.css">
|
||||
</dialog>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="fileSelector(name, multiple)"
|
||||
th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
|
||||
<script th:inline="javascript">
|
||||
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
||||
const multiple = [[${ multiple }]] || false;
|
||||
const remoteCall = [[${ remoteCall }]] || true;
|
||||
</script>
|
||||
<script src="js/downloader.js"></script>
|
||||
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
|
||||
<script th:inline="javascript">
|
||||
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
||||
const multiple = [[${multiple}]] || false;
|
||||
const remoteCall = [[${remoteCall}]] || true;
|
||||
</script>
|
||||
<script src="js/downloader.js"></script>
|
||||
|
||||
<div class="custom-file-chooser"
|
||||
th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple
|
||||
th:required="${notRequired} ? null : 'required'">
|
||||
</div>
|
||||
<div class="selected-files"></div>
|
||||
</div>
|
||||
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple th:required="${notRequired} ? null : 'required'">
|
||||
</div>
|
||||
<div class="selected-files"></div>
|
||||
</div>
|
||||
|
||||
<div class="progressBarContainer" style="display: none; position: relative;">
|
||||
<div class="progress" style="height: 1rem;">
|
||||
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar"
|
||||
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/fileInput.js"></script>
|
||||
<div class="progressBarContainer" style="display: none; position: relative;">
|
||||
<div class="progress" style="height: 1rem;">
|
||||
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/fileInput.js"></script>
|
||||
</th:block>
|
||||
@@ -112,41 +112,32 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div class="text-center">
|
||||
<img class="mb-4" src="favicon.svg?v=2" alt="favicon" width="144" height="144">
|
||||
|
||||
<div th:if="${oAuth2Enabled}">
|
||||
<a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a>
|
||||
<br>
|
||||
<div th:if="${error}" class="alert alert-danger text-danger text-center">
|
||||
<!-- oauth2AutoCreateDisabled -->
|
||||
<div th:if="${error == 'oauth2AutoCreateDisabled'}" th:text="#{login.oauth2AutoCreateDisabled}">OAuth2: Auto-Create User Disabled.</div>
|
||||
<!-- oauth2AuthenticationError -->
|
||||
<div th:if="${error == 'oauth2AuthenticationError'}" th:text="#{userAlreadyExistsMessage}">OAuth2: User already exists.</div>
|
||||
<!-- invalidUsername -->
|
||||
<div th:if="${error == 'invalidUsername'}" th:text="#{invalidUsernameMessage}">OAUTH2: Invalid username.</div>
|
||||
<!-- badcredentials -->
|
||||
<div th:if="${error == 'badcredentials'}" th:text="#{login.invalid}">Invalid username or password.</div>
|
||||
<!-- locked -->
|
||||
<div th:if="${error == 'locked'}" th:text="#{login.locked}">Your account has been locked. </div>
|
||||
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
|
||||
<div th:if="${oAuth2Enabled}">
|
||||
<a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a>
|
||||
<br>
|
||||
<br>
|
||||
<div th:if="${erroroauth}" class="alert alert-danger text-center">
|
||||
<div th:if="${erroroauth}" th:text="#{${erroroauth}}">OAuth2: Error Message</div>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="text-danger text-center">
|
||||
<div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
|
||||
<div th:if="${param.messageType != null and param.messageType.size() > 0 and param.messageType[0] == 'credsUpdated'}" class="alert alert-success">
|
||||
<span th:text="#{changedCredsMessage}">Default message if not found</span>
|
||||
|
||||
<div th:if="${error}" class="alert alert-danger text-danger text-center">
|
||||
<div th:if="${error}" th:text="#{${error}}">OAuth2: Error Message</div>
|
||||
</div>
|
||||
<div class="text-danger text-center">
|
||||
<div th:if="${logoutMessage}" class="alert alert-success" th:text="${logoutMessage}"></div>
|
||||
<div th:if="${messageType}" class="alert alert-success">
|
||||
<span th:text="#{${messageType}}">Default message if not found</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form th:action="@{login}" method="post">
|
||||
<div class="text-center">
|
||||
<img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144">
|
||||
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
|
||||
<div th:if="${oAuth2Enabled}">
|
||||
<a href="oauth2/authorization/oidc" class="w-100 btn btn-lg btn-primary" th:text="#{login.ssoSignIn}">Login Via SSO</a>
|
||||
<div class="text-danger text-center">
|
||||
<div th:if="${error == 'oauth2AutoCreateDisabled'}" th:text="#{login.oauth2AutoCreateDisabled}">OAUTH2 Auto-Create User Disabled.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
|
||||
<div class="form-floating">
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="admin">
|
||||
<label for="username" th:text="#{username}">Username</label>
|
||||
@@ -171,7 +162,7 @@
|
||||
<div class="dropdown-menu" aria-labelledby="languageDropdown">
|
||||
<!-- Here's where the fragment will be included -->
|
||||
<div class="scrollable-y">
|
||||
<th:block th:replace="~{fragments/languages :: langs}"></th:block>
|
||||
<th:block th:replace="~{fragments/languages :: langs}"></th:block>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,4 +171,4 @@
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
Reference in New Issue
Block a user