JS and css cleanup
This commit is contained in:
parent
7bdb2615d4
commit
45b3e0aa6a
14 changed files with 669 additions and 644 deletions
10
src/main/resources/static/css/fileSelect.css
Normal file
10
src/main/resources/static/css/fileSelect.css
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.custom-file-label {
|
||||||
|
padding-right: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-files {
|
||||||
|
margin-top: 10px;
|
||||||
|
max-height: 150px;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
76
src/main/resources/static/js/darkmode.js
Normal file
76
src/main/resources/static/js/darkmode.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
var toggleCount = 0;
|
||||||
|
var lastToggleTime = Date.now();
|
||||||
|
|
||||||
|
function toggleDarkMode() {
|
||||||
|
var currentTime = Date.now();
|
||||||
|
if (currentTime - lastToggleTime < 1000) {
|
||||||
|
toggleCount++;
|
||||||
|
} else {
|
||||||
|
toggleCount = 1;
|
||||||
|
}
|
||||||
|
lastToggleTime = currentTime;
|
||||||
|
|
||||||
|
var lightModeStyles = document.getElementById("light-mode-styles");
|
||||||
|
var darkModeStyles = document.getElementById("dark-mode-styles");
|
||||||
|
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
|
||||||
|
var darkModeIcon = document.getElementById("dark-mode-icon");
|
||||||
|
|
||||||
|
if (toggleCount >= 18) {
|
||||||
|
localStorage.setItem("dark-mode", "rainbow");
|
||||||
|
lightModeStyles.disabled = true;
|
||||||
|
darkModeStyles.disabled = true;
|
||||||
|
rainbowModeStyles.disabled = false;
|
||||||
|
darkModeIcon.src = "rainbow.svg";
|
||||||
|
} else if (localStorage.getItem("dark-mode") == "on") {
|
||||||
|
localStorage.setItem("dark-mode", "off");
|
||||||
|
lightModeStyles.disabled = false;
|
||||||
|
darkModeStyles.disabled = true;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "sun.svg";
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("dark-mode", "on");
|
||||||
|
lightModeStyles.disabled = true;
|
||||||
|
darkModeStyles.disabled = false;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "moon.svg";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
var lightModeStyles = document.getElementById("light-mode-styles");
|
||||||
|
var darkModeStyles = document.getElementById("dark-mode-styles");
|
||||||
|
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
|
||||||
|
var darkModeIcon = document.getElementById("dark-mode-icon");
|
||||||
|
|
||||||
|
if (localStorage.getItem("dark-mode") == "on") {
|
||||||
|
lightModeStyles.disabled = true;
|
||||||
|
darkModeStyles.disabled = false;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "moon.svg";
|
||||||
|
} else if (localStorage.getItem("dark-mode") == "off") {
|
||||||
|
lightModeStyles.disabled = false;
|
||||||
|
darkModeStyles.disabled = true;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "sun.svg";
|
||||||
|
} else if (localStorage.getItem("dark-mode") == "rainbow") {
|
||||||
|
lightModeStyles.disabled = true;
|
||||||
|
darkModeStyles.disabled = true;
|
||||||
|
rainbowModeStyles.disabled = false;
|
||||||
|
darkModeIcon.src = "rainbow.svg";
|
||||||
|
} else {
|
||||||
|
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
|
darkModeStyles.disabled = false;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "moon.svg";
|
||||||
|
} else {
|
||||||
|
darkModeStyles.disabled = true;
|
||||||
|
rainbowModeStyles.disabled = true;
|
||||||
|
darkModeIcon.src = "sun.svg";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("dark-mode-toggle").addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
toggleDarkMode();
|
||||||
|
});
|
||||||
|
});
|
242
src/main/resources/static/js/downloader.js
Normal file
242
src/main/resources/static/js/downloader.js
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
function showErrorBanner(message, stackTrace) {
|
||||||
|
const errorContainer = document.getElementById("errorContainer");
|
||||||
|
errorContainer.style.display = "block"; // Display the banner
|
||||||
|
document.querySelector("#errorContainer .alert-heading").textContent = "Error";
|
||||||
|
document.querySelector("#errorContainer p").textContent = message;
|
||||||
|
document.querySelector("#traceContent").textContent = stackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('form').submit(async function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const url = this.action;
|
||||||
|
const files = $('#fileInput-input')[0].files;
|
||||||
|
const formData = new FormData(this);
|
||||||
|
const override = $('#override').val() || '';
|
||||||
|
|
||||||
|
$('#submitBtn').text('Processing...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (override === 'multi' || files.length > 1 && override !== 'single') {
|
||||||
|
// Show the progress bar
|
||||||
|
$('#progressBarContainer').show();
|
||||||
|
// Initialize the progress bar
|
||||||
|
//let progressBar = $('#progressBar');
|
||||||
|
//progressBar.css('width', '0%');
|
||||||
|
//progressBar.attr('aria-valuenow', 0);
|
||||||
|
//progressBar.attr('aria-valuemax', files.length);
|
||||||
|
|
||||||
|
await submitMultiPdfForm(url, files);
|
||||||
|
} else {
|
||||||
|
const downloadDetails = await handleSingleDownload(url, formData);
|
||||||
|
const downloadOption = localStorage.getItem('downloadOption');
|
||||||
|
|
||||||
|
// Handle the download action according to the selected option
|
||||||
|
//handleDownloadAction(downloadOption, downloadDetails.blob, downloadDetails.filename);
|
||||||
|
|
||||||
|
// Update the progress bar
|
||||||
|
//updateProgressBar(progressBar, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#submitBtn').text('Submit');
|
||||||
|
} catch (error) {
|
||||||
|
handleDownloadError(error);
|
||||||
|
$('#submitBtn').text('Submit');
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleDownloadAction(downloadOption, blob, filename) {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
switch (downloadOption) {
|
||||||
|
case 'sameWindow':
|
||||||
|
// Open the file in the same window
|
||||||
|
window.location.href = url;
|
||||||
|
break;
|
||||||
|
case 'newWindow':
|
||||||
|
// Open the file in a new window
|
||||||
|
window.open(url, '_blank');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Download the file
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSingleDownload(url, formData) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, { method: 'POST', body: formData });
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
if (contentType && contentType.includes('application/json')) {
|
||||||
|
return handleJsonResponse(response);
|
||||||
|
console.error('Throwing error banner, response was not okay');
|
||||||
|
}
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentDisposition = response.headers.get('Content-Disposition');
|
||||||
|
let filename = getFilenameFromContentDisposition(contentDisposition);
|
||||||
|
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
if (contentType.includes('application/pdf') || contentType.includes('image/')) {
|
||||||
|
return handleResponse(blob, filename, true);
|
||||||
|
} else {
|
||||||
|
return handleResponse(blob, filename);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in handleSingleDownload:', error);
|
||||||
|
throw error; // Re-throw the error if you want it to be handled higher up.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFilenameFromContentDisposition(contentDisposition) {
|
||||||
|
let filename;
|
||||||
|
|
||||||
|
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
|
||||||
|
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
|
||||||
|
} else {
|
||||||
|
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
|
||||||
|
filename = 'download';
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function handleJsonResponse(response) {
|
||||||
|
const json = await response.json();
|
||||||
|
const errorMessage = JSON.stringify(json, null, 2);
|
||||||
|
if (errorMessage.toLowerCase().includes('the password is incorrect') || errorMessage.toLowerCase().includes('Password is not provided')) {
|
||||||
|
alert('[[#{error.pdfPassword}]]');
|
||||||
|
} else {
|
||||||
|
showErrorBanner(json.error + ':' + json.message, json.trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function handleResponse(blob, filename, considerViewOptions = false) {
|
||||||
|
if (!blob) return;
|
||||||
|
const downloadOption = localStorage.getItem('downloadOption');
|
||||||
|
if (considerViewOptions) {
|
||||||
|
if (downloadOption === 'sameWindow') {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
window.location.href = url;
|
||||||
|
return;
|
||||||
|
} else if (downloadOption === 'newWindow') {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
window.open(url, '_blank');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
downloadFile(blob, filename);
|
||||||
|
return { filename, blob };
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDownloadError(error) {
|
||||||
|
const errorMessage = error.message;
|
||||||
|
showErrorBanner(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
let urls = []; // An array to hold all the URLs
|
||||||
|
|
||||||
|
function downloadFile(blob, filename) {
|
||||||
|
if (!(blob instanceof Blob)) {
|
||||||
|
console.error('Invalid blob passed to downloadFile function');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
a.click();
|
||||||
|
urls.push(url); // Store the URL so it doesn't get garbage collected too soon
|
||||||
|
|
||||||
|
return { filename, blob };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function submitMultiPdfForm(url, files) {
|
||||||
|
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
||||||
|
const zipFiles = files.length > zipThreshold;
|
||||||
|
let jszip = null;
|
||||||
|
//let progressBar = $('#progressBar');
|
||||||
|
//progressBar.css('width', '0%');
|
||||||
|
//progressBar.attr('aria-valuenow', 0);
|
||||||
|
//progressBar.attr('aria-valuemax', Array.from(files).length);
|
||||||
|
if (zipFiles) {
|
||||||
|
jszip = new JSZip();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get existing form data
|
||||||
|
let formData = new FormData($('form')[0]);
|
||||||
|
formData.delete('fileInput');
|
||||||
|
|
||||||
|
const CONCURRENCY_LIMIT = 8;
|
||||||
|
const chunks = [];
|
||||||
|
for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) {
|
||||||
|
chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
const promises = chunk.map(async file => {
|
||||||
|
let fileFormData = new FormData();
|
||||||
|
fileFormData.append('fileInput', file);
|
||||||
|
|
||||||
|
// Add other form data
|
||||||
|
for (let pair of formData.entries()) {
|
||||||
|
fileFormData.append(pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const downloadDetails = await handleSingleDownload(url, fileFormData);
|
||||||
|
console.log(downloadDetails);
|
||||||
|
if (zipFiles) {
|
||||||
|
jszip.file(downloadDetails.filename, downloadDetails.blob);
|
||||||
|
} else {
|
||||||
|
downloadFile(downloadDetails.blob, downloadDetails.filename);
|
||||||
|
}
|
||||||
|
//updateProgressBar(progressBar, Array.from(files).length);
|
||||||
|
} catch (error) {
|
||||||
|
handleDownloadError(error);
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zipFiles) {
|
||||||
|
try {
|
||||||
|
const content = await jszip.generateAsync({ type: "blob" });
|
||||||
|
downloadFile(content, "files.zip");
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating ZIP file: ' + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updateProgressBar(progressBar, files) {
|
||||||
|
let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
|
||||||
|
progressBar.css('width', progress + '%');
|
||||||
|
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
|
||||||
|
}
|
||||||
|
window.addEventListener('unload', () => {
|
||||||
|
for (const url of urls) {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
});
|
50
src/main/resources/static/js/errorBanner.js
Normal file
50
src/main/resources/static/js/errorBanner.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
var traceVisible = false;
|
||||||
|
|
||||||
|
function toggletrace() {
|
||||||
|
var traceDiv = document.getElementById("trace");
|
||||||
|
if (!traceVisible) {
|
||||||
|
traceDiv.style.maxHeight = "500px";
|
||||||
|
traceVisible = true;
|
||||||
|
} else {
|
||||||
|
traceDiv.style.maxHeight = "0px";
|
||||||
|
traceVisible = false;
|
||||||
|
}
|
||||||
|
adjustContainerHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
function copytrace() {
|
||||||
|
var flip = false
|
||||||
|
if (!traceVisible) {
|
||||||
|
toggletrace()
|
||||||
|
flip = true
|
||||||
|
}
|
||||||
|
var traceContent = document.getElementById("traceContent");
|
||||||
|
var range = document.createRange();
|
||||||
|
range.selectNode(traceContent);
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
window.getSelection().addRange(range);
|
||||||
|
document.execCommand("copy");
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
if (flip) {
|
||||||
|
toggletrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismissError() {
|
||||||
|
var errorContainer = document.getElementById("errorContainer");
|
||||||
|
errorContainer.style.display = "none";
|
||||||
|
errorContainer.style.height = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjustContainerHeight() {
|
||||||
|
var errorContainer = document.getElementById("errorContainer");
|
||||||
|
var traceDiv = document.getElementById("trace");
|
||||||
|
if (traceVisible) {
|
||||||
|
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
|
||||||
|
} else {
|
||||||
|
errorContainer.style.height = "auto";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function showHelp() {
|
||||||
|
$('#helpModal').modal('show');
|
||||||
|
}
|
37
src/main/resources/static/js/favourites.js
Normal file
37
src/main/resources/static/js/favourites.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
function updateFavoritesDropdown() {
|
||||||
|
var dropdown = document.querySelector('#favoritesDropdown');
|
||||||
|
dropdown.innerHTML = ''; // Clear the current favorites
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var hasFavorites = false;
|
||||||
|
|
||||||
|
for (var i = 0; i < localStorage.length; i++) {
|
||||||
|
var key = localStorage.key(i);
|
||||||
|
if (localStorage.getItem(key) === 'favorite') {
|
||||||
|
// Find the corresponding navbar entry
|
||||||
|
var navbarEntry = document.querySelector(`a[href='${key}']`);
|
||||||
|
if (navbarEntry) {
|
||||||
|
// Create a new dropdown entry
|
||||||
|
var dropdownItem = document.createElement('a');
|
||||||
|
dropdownItem.className = 'dropdown-item';
|
||||||
|
dropdownItem.href = navbarEntry.href;
|
||||||
|
dropdownItem.innerHTML = navbarEntry.innerHTML;
|
||||||
|
dropdown.appendChild(dropdownItem);
|
||||||
|
hasFavorites = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show or hide the default item based on whether there are any favorites
|
||||||
|
if (!hasFavorites) {
|
||||||
|
var defaultItem = document.createElement('a');
|
||||||
|
defaultItem.className = 'dropdown-item';
|
||||||
|
defaultItem.textContent = noFavourites;
|
||||||
|
dropdown.appendChild(defaultItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
updateFavoritesDropdown();
|
||||||
|
});
|
45
src/main/resources/static/js/fileInput.js
Normal file
45
src/main/resources/static/js/fileInput.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const fileInput = document.getElementById(elementID);
|
||||||
|
|
||||||
|
// Prevent default behavior for drag events
|
||||||
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||||
|
fileInput.addEventListener(eventName, preventDefaults, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function preventDefaults(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add drop event listener
|
||||||
|
fileInput.addEventListener('drop', handleDrop, false);
|
||||||
|
|
||||||
|
function handleDrop(e) {
|
||||||
|
const dt = e.dataTransfer;
|
||||||
|
const files = dt.files;
|
||||||
|
fileInput.files = files;
|
||||||
|
handleFileInputChange(fileInput)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(elementID).on("change", function() {
|
||||||
|
handleFileInputChange(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleFileInputChange(inputElement) {
|
||||||
|
const files = $(inputElement).get(0).files;
|
||||||
|
const fileNames = Array.from(files).map(f => f.name);
|
||||||
|
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
|
||||||
|
selectedFilesContainer.empty();
|
||||||
|
fileNames.forEach(fileName => {
|
||||||
|
selectedFilesContainer.append("<div>" + fileName + "</div>");
|
||||||
|
});
|
||||||
|
console.log("fileNames.length=" + fileNames.length)
|
||||||
|
if (fileNames.length === 1) {
|
||||||
|
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
|
||||||
|
} else if (fileNames.length > 1) {
|
||||||
|
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + filesSelected);
|
||||||
|
} else {
|
||||||
|
$(inputElement).siblings(".custom-file-label").addClass("selected").html(pdfPrompt);
|
||||||
|
}
|
||||||
|
}
|
41
src/main/resources/static/js/githubVersion.js
Normal file
41
src/main/resources/static/js/githubVersion.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
function compareVersions(version1, version2) {
|
||||||
|
const v1 = version1.split('.');
|
||||||
|
const v2 = version2.split('.');
|
||||||
|
|
||||||
|
for (let i = 0; i < v1.length || i < v2.length; i++) {
|
||||||
|
const n1 = parseInt(v1[i]) || 0;
|
||||||
|
const n2 = parseInt(v2[i]) || 0;
|
||||||
|
|
||||||
|
if (n1 > n2) {
|
||||||
|
return 1;
|
||||||
|
} else if (n1 < n2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLatestReleaseVersion() {
|
||||||
|
const url = "https://api.github.com/repos/Frooodle/Stirling-PDF/releases/latest";
|
||||||
|
const response = await fetch(url);
|
||||||
|
const data = await response.json();
|
||||||
|
return data.tag_name.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function checkForUpdate() {
|
||||||
|
const latestVersion = await getLatestReleaseVersion();
|
||||||
|
console.log("latestVersion=" + latestVersion)
|
||||||
|
console.log("currentVersion=" + currentVersion)
|
||||||
|
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion))
|
||||||
|
if (latestVersion != null && latestVersion != "" && compareVersions(latestVersion, currentVersion) > 0) {
|
||||||
|
document.getElementById("update-btn").style.display = "block";
|
||||||
|
console.log("visible")
|
||||||
|
} else {
|
||||||
|
document.getElementById("update-btn").style.display = "none";
|
||||||
|
console.log("hidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdate();
|
46
src/main/resources/static/js/languageSelection.js
Normal file
46
src/main/resources/static/js/languageSelection.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const defaultLocale = document.documentElement.lang || 'en_GB';
|
||||||
|
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
||||||
|
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
|
||||||
|
|
||||||
|
for (let i = 0; i < dropdownItems.length; i++) {
|
||||||
|
const item = dropdownItems[i];
|
||||||
|
item.classList.remove('active');
|
||||||
|
if (item.dataset.languageCode === storedLocale) {
|
||||||
|
item.classList.add('active');
|
||||||
|
}
|
||||||
|
item.addEventListener('click', handleDropdownItemClick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleDropdownItemClick(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const languageCode = this.dataset.languageCode;
|
||||||
|
localStorage.setItem('languageCode', languageCode);
|
||||||
|
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
if (currentUrl.indexOf('?lang=') === -1) {
|
||||||
|
window.location.href = currentUrl + '?lang=' + languageCode;
|
||||||
|
} else {
|
||||||
|
window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(".nav-item.dropdown").each(function() {
|
||||||
|
var $dropdownMenu = $(this).find(".dropdown-menu");
|
||||||
|
if ($dropdownMenu.children().length <= 2 && $dropdownMenu.children("hr.dropdown-divider").length === $dropdownMenu.children().length) {
|
||||||
|
$(this).prev('.nav-item.nav-item-separator').remove();
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Sort languages by alphabet
|
||||||
|
var list = $('.dropdown-menu[aria-labelledby="languageDropdown"]').children("a");
|
||||||
|
list.sort(function(a, b) {
|
||||||
|
var A = $(a).text().toUpperCase();
|
||||||
|
var B = $(b).text().toUpperCase();
|
||||||
|
return (A < B) ? -1 : (A > B) ? 1 : 0;
|
||||||
|
})
|
||||||
|
.appendTo('.dropdown-menu[aria-labelledby="languageDropdown"]');
|
||||||
|
});
|
63
src/main/resources/static/js/merge.js
Normal file
63
src/main/resources/static/js/merge.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
document.getElementById("fileInput-input").addEventListener("change", function() {
|
||||||
|
var files = this.files;
|
||||||
|
var list = document.getElementById("selectedFiles");
|
||||||
|
list.innerHTML = "";
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var item = document.createElement("li");
|
||||||
|
item.className = "list-group-item";
|
||||||
|
item.innerHTML = `
|
||||||
|
<div class="d-flex justify-content-between align-items-center w-100">
|
||||||
|
<div class="filename">${files[i].name}</div>
|
||||||
|
<div class="arrows d-flex">
|
||||||
|
<button class="btn btn-secondary move-up"><span>↑</span></button>
|
||||||
|
<button class="btn btn-secondary move-down"><span>↓</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
list.appendChild(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
var moveUpButtons = document.querySelectorAll(".move-up");
|
||||||
|
for (var i = 0; i < moveUpButtons.length; i++) {
|
||||||
|
moveUpButtons[i].addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var parent = this.closest(".list-group-item");
|
||||||
|
var grandParent = parent.parentNode;
|
||||||
|
if (parent.previousElementSibling) {
|
||||||
|
grandParent.insertBefore(parent, parent.previousElementSibling);
|
||||||
|
updateFiles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var moveDownButtons = document.querySelectorAll(".move-down");
|
||||||
|
for (var i = 0; i < moveDownButtons.length; i++) {
|
||||||
|
moveDownButtons[i].addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
var parent = this.closest(".list-group-item");
|
||||||
|
var grandParent = parent.parentNode;
|
||||||
|
if (parent.nextElementSibling) {
|
||||||
|
grandParent.insertBefore(parent.nextElementSibling, parent);
|
||||||
|
updateFiles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFiles() {
|
||||||
|
var dataTransfer = new DataTransfer();
|
||||||
|
var liElements = document.querySelectorAll("#selectedFiles li");
|
||||||
|
|
||||||
|
for (var i = 0; i < liElements.length; i++) {
|
||||||
|
var fileNameFromList = liElements[i].querySelector(".filename").innerText;
|
||||||
|
var fileFromFiles;
|
||||||
|
for (var j = 0; j < files.length; j++) {
|
||||||
|
var file = files[j];
|
||||||
|
if (file.name === fileNameFromList) {
|
||||||
|
dataTransfer.items.add(file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById("fileInput-input").files = dataTransfer.files;
|
||||||
|
}
|
||||||
|
});
|
42
src/main/resources/static/js/settings.js
Normal file
42
src/main/resources/static/js/settings.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
|
||||||
|
var downloadOption = localStorage.getItem('downloadOption')
|
||||||
|
|| 'sameWindow';
|
||||||
|
|
||||||
|
// Set the selected option in the dropdown
|
||||||
|
document.getElementById('downloadOption').value = downloadOption;
|
||||||
|
|
||||||
|
|
||||||
|
// Save the selected option to local storage when the dropdown value changes
|
||||||
|
document.getElementById('downloadOption').addEventListener(
|
||||||
|
'change',
|
||||||
|
function() {
|
||||||
|
downloadOption = this.value;
|
||||||
|
localStorage.setItem('downloadOption',
|
||||||
|
downloadOption);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist
|
||||||
|
var zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
||||||
|
|
||||||
|
// Set the value of the slider and the display span
|
||||||
|
document.getElementById('zipThreshold').value = zipThreshold;
|
||||||
|
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Save the selected value to local storage when the slider value changes
|
||||||
|
document.getElementById('zipThreshold').addEventListener('input', function() {
|
||||||
|
zipThreshold = this.value;
|
||||||
|
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
||||||
|
localStorage.setItem('zipThreshold', zipThreshold);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled';
|
||||||
|
document.getElementById('boredWaiting').checked = boredWaiting === 'enabled';
|
||||||
|
|
||||||
|
document.getElementById('boredWaiting').addEventListener('change', function() {
|
||||||
|
boredWaiting = this.checked ? 'enabled' : 'disabled';
|
||||||
|
localStorage.setItem('boredWaiting', boredWaiting);
|
||||||
|
});
|
|
@ -34,84 +34,7 @@
|
||||||
<script src="js/tab-container.js"></script>
|
<script src="js/tab-container.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script src="js/darkmode.js"></script>
|
||||||
var toggleCount = 0;
|
|
||||||
var lastToggleTime = Date.now();
|
|
||||||
|
|
||||||
function toggleDarkMode() {
|
|
||||||
var currentTime = Date.now();
|
|
||||||
if (currentTime - lastToggleTime < 1000) {
|
|
||||||
toggleCount++;
|
|
||||||
} else {
|
|
||||||
toggleCount = 1;
|
|
||||||
}
|
|
||||||
lastToggleTime = currentTime;
|
|
||||||
|
|
||||||
var lightModeStyles = document.getElementById("light-mode-styles");
|
|
||||||
var darkModeStyles = document.getElementById("dark-mode-styles");
|
|
||||||
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
|
|
||||||
var darkModeIcon = document.getElementById("dark-mode-icon");
|
|
||||||
|
|
||||||
if (toggleCount >= 18) {
|
|
||||||
localStorage.setItem("dark-mode", "rainbow");
|
|
||||||
lightModeStyles.disabled = true;
|
|
||||||
darkModeStyles.disabled = true;
|
|
||||||
rainbowModeStyles.disabled = false;
|
|
||||||
darkModeIcon.src = "rainbow.svg";
|
|
||||||
} else if (localStorage.getItem("dark-mode") == "on") {
|
|
||||||
localStorage.setItem("dark-mode", "off");
|
|
||||||
lightModeStyles.disabled = false;
|
|
||||||
darkModeStyles.disabled = true;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "sun.svg";
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("dark-mode", "on");
|
|
||||||
lightModeStyles.disabled = true;
|
|
||||||
darkModeStyles.disabled = false;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "moon.svg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
var lightModeStyles = document.getElementById("light-mode-styles");
|
|
||||||
var darkModeStyles = document.getElementById("dark-mode-styles");
|
|
||||||
var rainbowModeStyles = document.getElementById("rainbow-mode-styles");
|
|
||||||
var darkModeIcon = document.getElementById("dark-mode-icon");
|
|
||||||
|
|
||||||
if (localStorage.getItem("dark-mode") == "on") {
|
|
||||||
lightModeStyles.disabled = true;
|
|
||||||
darkModeStyles.disabled = false;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "moon.svg";
|
|
||||||
} else if (localStorage.getItem("dark-mode") == "off") {
|
|
||||||
lightModeStyles.disabled = false;
|
|
||||||
darkModeStyles.disabled = true;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "sun.svg";
|
|
||||||
} else if (localStorage.getItem("dark-mode") == "rainbow") {
|
|
||||||
lightModeStyles.disabled = true;
|
|
||||||
darkModeStyles.disabled = true;
|
|
||||||
rainbowModeStyles.disabled = false;
|
|
||||||
darkModeIcon.src = "rainbow.svg";
|
|
||||||
} else {
|
|
||||||
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
||||||
darkModeStyles.disabled = false;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "moon.svg";
|
|
||||||
} else {
|
|
||||||
darkModeStyles.disabled = true;
|
|
||||||
rainbowModeStyles.disabled = true;
|
|
||||||
darkModeIcon.src = "sun.svg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("dark-mode-toggle").addEventListener("click", function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
toggleDarkMode();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -168,214 +91,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
|
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
|
||||||
<script>
|
<script src="js/downloader.js"></script>
|
||||||
function showErrorBanner(message, stackTrace) {
|
|
||||||
const errorContainer = document.getElementById("errorContainer");
|
|
||||||
errorContainer.style.display = "block"; // Display the banner
|
|
||||||
document.querySelector("#errorContainer .alert-heading").textContent = "Error";
|
|
||||||
document.querySelector("#errorContainer p").textContent = message;
|
|
||||||
document.querySelector("#traceContent").textContent = stackTrace;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
$('form').submit(async function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const url = this.action;
|
|
||||||
const files = $('#fileInput-input')[0].files;
|
|
||||||
const formData = new FormData(this);
|
|
||||||
const override = $('#override').val() || '';
|
|
||||||
|
|
||||||
$('#submitBtn').text('Processing...');
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (override === 'multi' || files.length > 1 && override !== 'single') {
|
|
||||||
await submitMultiPdfForm(url, files);
|
|
||||||
} else {
|
|
||||||
const downloadDetails = await handleSingleDownload(url, formData);
|
|
||||||
|
|
||||||
// Determine the download option from localStorage
|
|
||||||
const downloadOption = localStorage.getItem('downloadOption');
|
|
||||||
|
|
||||||
// Handle the download action according to the selected option
|
|
||||||
handleDownloadAction(downloadOption, downloadDetails.blob, downloadDetails.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#submitBtn').text('Submit');
|
|
||||||
} catch (error) {
|
|
||||||
handleDownloadError(error);
|
|
||||||
$('#submitBtn').text('Submit');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleDownloadAction(downloadOption, blob, filename) {
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
switch (downloadOption) {
|
|
||||||
case 'sameWindow':
|
|
||||||
// Open the file in the same window
|
|
||||||
window.location.href = url;
|
|
||||||
break;
|
|
||||||
case 'newWindow':
|
|
||||||
// Open the file in a new window
|
|
||||||
window.open(url, '_blank');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Download the file
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.download = filename;
|
|
||||||
link.click();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleSingleDownload(url, formData) {
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
|
||||||
} else {
|
|
||||||
const blob = await response.blob();
|
|
||||||
const filename = getFilenameFromContentDisposition(response.headers.get('Content-Disposition'));
|
|
||||||
return { blob, filename };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function getFilenameFromContentDisposition(contentDisposition) {
|
|
||||||
let filename;
|
|
||||||
|
|
||||||
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
|
|
||||||
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, ''));
|
|
||||||
} else {
|
|
||||||
// If the Content-Disposition header is not present or does not contain the filename, use a default filename
|
|
||||||
filename = 'download';
|
|
||||||
}
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function handlePdfOrImageResponse(response, filename) {
|
|
||||||
const downloadOption = localStorage.getItem('downloadOption');
|
|
||||||
const blob = await response.blob();
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
if (downloadOption === 'sameWindow') {
|
|
||||||
window.location.href = url;
|
|
||||||
} else if (downloadOption === 'newWindow') {
|
|
||||||
window.open(url, '_blank');
|
|
||||||
} else {
|
|
||||||
downloadFile(url, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleJsonResponse(response) {
|
|
||||||
const json = await response.json();
|
|
||||||
const errorMessage = JSON.stringify(json, null, 2);
|
|
||||||
if(errorMessage.toLowerCase().includes('the password is incorrect') || errorMessage.toLowerCase().includes('Password is not provided')){
|
|
||||||
alert('[[#{error.pdfPassword}]]');
|
|
||||||
} else {
|
|
||||||
showErrorBanner(json.error + ':' + json.message, json.trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleOtherResponse(response, filename) {
|
|
||||||
const blob = await response.blob();
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
downloadFile(url, filename);
|
|
||||||
}
|
|
||||||
function handleDownloadError(error) {
|
|
||||||
const errorMessage = error.message;
|
|
||||||
showErrorBanner(errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
let urls = []; // An array to hold all the URLs
|
|
||||||
|
|
||||||
function downloadFile(blob, filename) {
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = url;
|
|
||||||
a.download = filename;
|
|
||||||
a.click();
|
|
||||||
urls.push(url); // Store the URL so it doesn't get garbage collected too soon
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function submitMultiPdfForm(url, files) {
|
|
||||||
const zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
|
||||||
const zipFiles = files.length > zipThreshold;
|
|
||||||
let jszip = null;
|
|
||||||
let progressBar = $('#progressBar');
|
|
||||||
progressBar.css('width', '0%');
|
|
||||||
progressBar.attr('aria-valuenow', 0);
|
|
||||||
progressBar.attr('aria-valuemax', Array.from(files).length);
|
|
||||||
if (zipFiles) {
|
|
||||||
jszip = new JSZip();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get existing form data
|
|
||||||
let formData = new FormData($('form')[0]);
|
|
||||||
formData.delete('fileInput');
|
|
||||||
|
|
||||||
const CONCURRENCY_LIMIT = 8;
|
|
||||||
const chunks = [];
|
|
||||||
for (let i = 0; i < Array.from(files).length; i += CONCURRENCY_LIMIT) {
|
|
||||||
chunks.push(Array.from(files).slice(i, i + CONCURRENCY_LIMIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
const promises = chunk.map(async file => {
|
|
||||||
let fileFormData = new FormData();
|
|
||||||
fileFormData.append('fileInput', file);
|
|
||||||
|
|
||||||
// Add other form data
|
|
||||||
for (let pair of formData.entries()) {
|
|
||||||
fileFormData.append(pair[0], pair[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const downloadDetails = await handleSingleDownload(url, fileFormData);
|
|
||||||
if (zipFiles) {
|
|
||||||
jszip.file(downloadDetails.filename, downloadDetails.blob);
|
|
||||||
} else {
|
|
||||||
downloadFile(downloadDetails.blob, downloadDetails.filename);
|
|
||||||
}
|
|
||||||
updateProgressBar(progressBar, Array.from(files).length);
|
|
||||||
} catch (error) {
|
|
||||||
handleDownloadError(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zipFiles) {
|
|
||||||
try {
|
|
||||||
const content = await jszip.generateAsync({ type: "blob" });
|
|
||||||
downloadFile(content, "files.zip");
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error generating ZIP file: ' + error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function updateProgressBar(progressBar, files) {
|
|
||||||
let progress = ((progressBar.attr('aria-valuenow') / files.length) * 100) + (100 / files.length);
|
|
||||||
progressBar.css('width', progress + '%');
|
|
||||||
progressBar.attr('aria-valuenow', parseInt(progressBar.attr('aria-valuenow')) + 1);
|
|
||||||
}
|
|
||||||
window.addEventListener('unload', () => {
|
|
||||||
for (const url of urls) {
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="custom-file-chooser">
|
<div class="custom-file-chooser">
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
|
@ -394,65 +110,12 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">Bored waiting?</button>
|
<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">Bored waiting?</button>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
const elementID = /*[[${name+"-input"}]]*/ '';
|
||||||
const fileInput = document.getElementById([[${name+"-input"}]]);
|
const filesSelected = /*[[#{filesSelected}]]*/ '';
|
||||||
|
const pdfPrompt = /*[[#{pdfPrompt}]]*/ '';
|
||||||
// Prevent default behavior for drag events
|
|
||||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
|
||||||
fileInput.addEventListener(eventName, preventDefaults, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
function preventDefaults(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add drop event listener
|
|
||||||
fileInput.addEventListener('drop', handleDrop, false);
|
|
||||||
|
|
||||||
function handleDrop(e) {
|
|
||||||
const dt = e.dataTransfer;
|
|
||||||
const files = dt.files;
|
|
||||||
fileInput.files = files;
|
|
||||||
handleFileInputChange(fileInput)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$([[${"#"+name+"-input"}]]).on("change", function() {
|
|
||||||
handleFileInputChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleFileInputChange(inputElement) {
|
|
||||||
const files = $(inputElement).get(0).files;
|
|
||||||
const fileNames = Array.from(files).map(f => f.name);
|
|
||||||
const selectedFilesContainer = $(inputElement).siblings(".selected-files");
|
|
||||||
selectedFilesContainer.empty();
|
|
||||||
fileNames.forEach(fileName => {
|
|
||||||
selectedFilesContainer.append("<div>" + fileName + "</div>");
|
|
||||||
});
|
|
||||||
console.log("fileNames.length=" + fileNames.length)
|
|
||||||
if (fileNames.length === 1) {
|
|
||||||
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames[0]);
|
|
||||||
} else if (fileNames.length > 1) {
|
|
||||||
$(inputElement).siblings(".custom-file-label").addClass("selected").html(fileNames.length + " " + [[#{filesSelected}]]);
|
|
||||||
} else {
|
|
||||||
$(inputElement).siblings(".custom-file-label").addClass("selected").html([[#{pdfPrompt}]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<script src="js/fileInput.js"></script>
|
||||||
.custom-file-label {
|
<link rel="stylesheet" href="css/fileSelect.css">
|
||||||
padding-right: 90px;
|
|
||||||
}
|
|
||||||
.selected-files {
|
|
||||||
margin-top: 10px;
|
|
||||||
max-height: 150px;
|
|
||||||
overflow-y: auto;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</th:block>
|
</th:block>
|
|
@ -54,56 +54,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script src="js/errorBanner.js"></script>
|
||||||
var traceVisible = false;
|
|
||||||
|
|
||||||
function toggletrace() {
|
|
||||||
var traceDiv = document.getElementById("trace");
|
|
||||||
if (!traceVisible) {
|
|
||||||
traceDiv.style.maxHeight = "500px";
|
|
||||||
traceVisible = true;
|
|
||||||
} else {
|
|
||||||
traceDiv.style.maxHeight = "0px";
|
|
||||||
traceVisible = false;
|
|
||||||
}
|
|
||||||
adjustContainerHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
function copytrace() {
|
|
||||||
var flip = false
|
|
||||||
if(!traceVisible) {
|
|
||||||
toggletrace()
|
|
||||||
flip = true
|
|
||||||
}
|
|
||||||
var traceContent = document.getElementById("traceContent");
|
|
||||||
var range = document.createRange();
|
|
||||||
range.selectNode(traceContent);
|
|
||||||
window.getSelection().removeAllRanges();
|
|
||||||
window.getSelection().addRange(range);
|
|
||||||
document.execCommand("copy");
|
|
||||||
window.getSelection().removeAllRanges();
|
|
||||||
if(flip){
|
|
||||||
toggletrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dismissError() {
|
|
||||||
var errorContainer = document.getElementById("errorContainer");
|
|
||||||
errorContainer.style.display = "none";
|
|
||||||
errorContainer.style.height ="0";
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjustContainerHeight() {
|
|
||||||
var errorContainer = document.getElementById("errorContainer");
|
|
||||||
var traceDiv = document.getElementById("trace");
|
|
||||||
if (traceVisible) {
|
|
||||||
errorContainer.style.height = errorContainer.scrollHeight - traceDiv.scrollHeight + traceDiv.offsetHeight + "px";
|
|
||||||
} else {
|
|
||||||
errorContainer.style.height = "auto";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function showHelp() {
|
|
||||||
$('#helpModal').modal('show');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</th:block>
|
</th:block>
|
|
@ -1,78 +1,11 @@
|
||||||
<div th:fragment="navbar" class="mx-auto">
|
<div th:fragment="navbar" class="mx-auto">
|
||||||
<script>
|
<script src="js/languageSelection.js"></script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
const defaultLocale = document.documentElement.lang || 'en_GB';
|
|
||||||
const storedLocale = localStorage.getItem('languageCode') || defaultLocale;
|
|
||||||
const dropdownItems = document.querySelectorAll('.lang_dropdown-item');
|
|
||||||
|
|
||||||
for (let i = 0; i < dropdownItems.length; i++) {
|
|
||||||
const item = dropdownItems[i];
|
|
||||||
item.classList.remove('active');
|
|
||||||
if (item.dataset.languageCode === storedLocale) {
|
|
||||||
item.classList.add('active');
|
|
||||||
}
|
|
||||||
item.addEventListener('click', handleDropdownItemClick);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleDropdownItemClick(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const languageCode = this.dataset.languageCode;
|
|
||||||
localStorage.setItem('languageCode', languageCode);
|
|
||||||
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
if (currentUrl.indexOf('?lang=') === -1) {
|
|
||||||
window.location.href = currentUrl + '?lang=' + languageCode;
|
|
||||||
} else {
|
|
||||||
window.location.href = currentUrl.replace(/\?lang=\w{2,}/, '?lang=' + languageCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
function compareVersions(version1, version2) {
|
const currentVersion = /*[[${@appVersion}]]*/ '';
|
||||||
const v1 = version1.split('.');
|
const noFavourites = /*[[#{noFavourites}]]*/ '';
|
||||||
const v2 = version2.split('.');
|
|
||||||
|
|
||||||
for (let i = 0; i < v1.length || i < v2.length; i++) {
|
|
||||||
const n1 = parseInt(v1[i]) || 0;
|
|
||||||
const n2 = parseInt(v2[i]) || 0;
|
|
||||||
|
|
||||||
if (n1 > n2) {
|
|
||||||
return 1;
|
|
||||||
} else if (n1 < n2) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestReleaseVersion() {
|
|
||||||
const url = "https://api.github.com/repos/Frooodle/Stirling-PDF/releases/latest";
|
|
||||||
const response = await fetch(url);
|
|
||||||
const data = await response.json();
|
|
||||||
return data.tag_name.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentVersion = /*[[${@appVersion}]]*/ ''; // Replace with your current version number
|
|
||||||
|
|
||||||
async function checkForUpdate() {
|
|
||||||
const latestVersion = await getLatestReleaseVersion();
|
|
||||||
console.log("latestVersion=" + latestVersion)
|
|
||||||
console.log("currentVersion=" + currentVersion)
|
|
||||||
console.log("compareVersions(latestVersion, currentVersion) > 0)=" + compareVersions(latestVersion, currentVersion))
|
|
||||||
if (latestVersion != null && latestVersion != "" && compareVersions(latestVersion, currentVersion) > 0) {
|
|
||||||
document.getElementById("update-btn").style.display = "block";
|
|
||||||
console.log("visible")
|
|
||||||
} else {
|
|
||||||
document.getElementById("update-btn").style.display = "none";
|
|
||||||
console.log("hidden")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkForUpdate();
|
|
||||||
</script>
|
</script>
|
||||||
|
<script th:src="@{/js/githubVersion.js}"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/navbar.css">
|
<link rel="stylesheet" href="css/navbar.css">
|
||||||
|
|
||||||
|
@ -263,48 +196,7 @@ function compareVersions(version1, version2) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script th:inline="javascript">
|
<script src="js/favourites.js"></script>
|
||||||
|
|
||||||
|
|
||||||
function updateFavoritesDropdown() {
|
|
||||||
var dropdown = document.querySelector('#favoritesDropdown');
|
|
||||||
dropdown.innerHTML = ''; // Clear the current favorites
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var hasFavorites = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < localStorage.length; i++) {
|
|
||||||
var key = localStorage.key(i);
|
|
||||||
if (localStorage.getItem(key) === 'favorite') {
|
|
||||||
// Find the corresponding navbar entry
|
|
||||||
var navbarEntry = document.querySelector(`a[href='${key}']`);
|
|
||||||
if (navbarEntry) {
|
|
||||||
// Create a new dropdown entry
|
|
||||||
var dropdownItem = document.createElement('a');
|
|
||||||
dropdownItem.className = 'dropdown-item';
|
|
||||||
dropdownItem.href = navbarEntry.href;
|
|
||||||
dropdownItem.innerHTML = navbarEntry.innerHTML;
|
|
||||||
dropdown.appendChild(dropdownItem);
|
|
||||||
hasFavorites = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show or hide the default item based on whether there are any favorites
|
|
||||||
if(!hasFavorites){
|
|
||||||
var defaultItem = document.createElement('a');
|
|
||||||
defaultItem.className = 'dropdown-item';
|
|
||||||
defaultItem.textContent = [[#{noFavourites}]]
|
|
||||||
dropdown.appendChild(defaultItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
|
|
||||||
updateFavoritesDropdown();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div>
|
<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div>
|
||||||
|
@ -363,73 +255,7 @@ function compareVersions(version1, version2) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script src="js/settings.js"></script>
|
||||||
$(document).ready(function() {
|
|
||||||
$(".nav-item.dropdown").each(function() {
|
|
||||||
var $dropdownMenu = $(this).find(".dropdown-menu");
|
|
||||||
if ($dropdownMenu.children().length <= 2 && $dropdownMenu.children("hr.dropdown-divider").length === $dropdownMenu.children().length) {
|
|
||||||
$(this).prev('.nav-item.nav-item-separator').remove();
|
|
||||||
$(this).remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Sort languages by alphabet
|
|
||||||
var list = $('.dropdown-menu[aria-labelledby="languageDropdown"]').children("a");
|
|
||||||
list.sort(function(a, b) {
|
|
||||||
var A = $(a).text().toUpperCase();
|
|
||||||
var B = $(b).text().toUpperCase();
|
|
||||||
return (A < B) ? -1 : (A > B) ? 1 : 0;
|
|
||||||
})
|
|
||||||
.appendTo('.dropdown-menu[aria-labelledby="languageDropdown"]');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
|
|
||||||
var downloadOption = localStorage.getItem('downloadOption')
|
|
||||||
|| 'sameWindow';
|
|
||||||
|
|
||||||
// Set the selected option in the dropdown
|
|
||||||
document.getElementById('downloadOption').value = downloadOption;
|
|
||||||
|
|
||||||
|
|
||||||
// Save the selected option to local storage when the dropdown value changes
|
|
||||||
document.getElementById('downloadOption').addEventListener(
|
|
||||||
'change',
|
|
||||||
function() {
|
|
||||||
downloadOption = this.value;
|
|
||||||
localStorage.setItem('downloadOption',
|
|
||||||
downloadOption);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Get the zipThreshold value from local storage, or set it to 0 if it doesn't exist
|
|
||||||
var zipThreshold = parseInt(localStorage.getItem('zipThreshold'), 10) || 4;
|
|
||||||
|
|
||||||
// Set the value of the slider and the display span
|
|
||||||
document.getElementById('zipThreshold').value = zipThreshold;
|
|
||||||
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Save the selected value to local storage when the slider value changes
|
|
||||||
document.getElementById('zipThreshold').addEventListener('input', function () {
|
|
||||||
zipThreshold = this.value;
|
|
||||||
document.getElementById('zipThresholdValue').textContent = zipThreshold;
|
|
||||||
localStorage.setItem('zipThreshold', zipThreshold);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var boredWaiting = localStorage.getItem('boredWaiting') || 'disabled';
|
|
||||||
document.getElementById('boredWaiting').checked = boredWaiting === 'enabled';
|
|
||||||
|
|
||||||
document.getElementById('boredWaiting').addEventListener('change', function() {
|
|
||||||
boredWaiting = this.checked ? 'enabled' : 'disabled';
|
|
||||||
localStorage.setItem('boredWaiting', boredWaiting);
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,72 +27,7 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<link rel="stylesheet" href="css/merge.css">
|
<link rel="stylesheet" href="css/merge.css">
|
||||||
<script>
|
<script src="js/merge.js"></script>
|
||||||
document.getElementById("fileInput-input").addEventListener("change", function() {
|
|
||||||
var files = this.files;
|
|
||||||
var list = document.getElementById("selectedFiles");
|
|
||||||
list.innerHTML = "";
|
|
||||||
for (var i = 0; i < files.length; i++) {
|
|
||||||
var item = document.createElement("li");
|
|
||||||
item.className = "list-group-item";
|
|
||||||
item.innerHTML = `
|
|
||||||
<div class="d-flex justify-content-between align-items-center w-100">
|
|
||||||
<div class="filename">${files[i].name}</div>
|
|
||||||
<div class="arrows d-flex">
|
|
||||||
<button class="btn btn-secondary move-up"><span>↑</span></button>
|
|
||||||
<button class="btn btn-secondary move-down"><span>↓</span></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
list.appendChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
var moveUpButtons = document.querySelectorAll(".move-up");
|
|
||||||
for (var i = 0; i < moveUpButtons.length; i++) {
|
|
||||||
moveUpButtons[i].addEventListener("click", function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
var parent = this.closest(".list-group-item");
|
|
||||||
var grandParent = parent.parentNode;
|
|
||||||
if (parent.previousElementSibling) {
|
|
||||||
grandParent.insertBefore(parent, parent.previousElementSibling);
|
|
||||||
updateFiles();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var moveDownButtons = document.querySelectorAll(".move-down");
|
|
||||||
for (var i = 0; i < moveDownButtons.length; i++) {
|
|
||||||
moveDownButtons[i].addEventListener("click", function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
var parent = this.closest(".list-group-item");
|
|
||||||
var grandParent = parent.parentNode;
|
|
||||||
if (parent.nextElementSibling) {
|
|
||||||
grandParent.insertBefore(parent.nextElementSibling, parent);
|
|
||||||
updateFiles();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFiles() {
|
|
||||||
var dataTransfer = new DataTransfer();
|
|
||||||
var liElements = document.querySelectorAll("#selectedFiles li");
|
|
||||||
|
|
||||||
for (var i = 0; i < liElements.length; i++) {
|
|
||||||
var fileNameFromList = liElements[i].querySelector(".filename").innerText;
|
|
||||||
var fileFromFiles;
|
|
||||||
for (var j = 0; j < files.length; j++) {
|
|
||||||
var file = files[j];
|
|
||||||
if (file.name === fileNameFromList) {
|
|
||||||
dataTransfer.items.add(file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.getElementById("fileInput-input").files = dataTransfer.files;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue