mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	JS and css cleanup
This commit is contained in:
		
							parent
							
								
									7bdb2615d4
								
							
						
					
					
						commit
						45b3e0aa6a
					
				
							
								
								
									
										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>
 | 
			
		||||
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>
 | 
			
		||||
<script src="js/darkmode.js"></script>
 | 
			
		||||
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
@ -168,214 +91,7 @@ document.addEventListener("DOMContentLoaded", function () {
 | 
			
		||||
</th:block>
 | 
			
		||||
 | 
			
		||||
<th:block th:fragment="fileSelector(name, multiple)"  th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: 'true', notRequired=${notRequired} ?: false">
 | 
			
		||||
    <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>
 | 
			
		||||
    <script src="js/downloader.js"></script>
 | 
			
		||||
 | 
			
		||||
    <div class="custom-file-chooser">
 | 
			
		||||
        <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>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
	<script th:inline="javascript">
 | 
			
		||||
        document.addEventListener('DOMContentLoaded', function () {
 | 
			
		||||
            const fileInput = document.getElementById([[${name+"-input"}]]);
 | 
			
		||||
 | 
			
		||||
            // 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}]]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
		const elementID =  /*[[${name+"-input"}]]*/ '';
 | 
			
		||||
		const filesSelected =  /*[[#{filesSelected}]]*/ '';
 | 
			
		||||
		const pdfPrompt =  /*[[#{pdfPrompt}]]*/ '';
 | 
			
		||||
	</script>
 | 
			
		||||
	
 | 
			
		||||
    <style>
 | 
			
		||||
        .custom-file-label {
 | 
			
		||||
            padding-right: 90px;
 | 
			
		||||
        }
 | 
			
		||||
        .selected-files {
 | 
			
		||||
            margin-top: 10px;
 | 
			
		||||
            max-height: 150px;
 | 
			
		||||
            overflow-y: auto;
 | 
			
		||||
            white-space: pre-wrap;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
    
 | 
			
		||||
    <script src="js/fileInput.js"></script>
 | 
			
		||||
    <link rel="stylesheet" href="css/fileSelect.css">
 | 
			
		||||
</th:block>
 | 
			
		||||
@ -54,56 +54,5 @@
 | 
			
		||||
	    </div>
 | 
			
		||||
	  </div>
 | 
			
		||||
	</div>
 | 
			
		||||
  <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>
 | 
			
		||||
  <script src="js/errorBanner.js"></script>
 | 
			
		||||
</th:block>
 | 
			
		||||
@ -1,78 +1,11 @@
 | 
			
		||||
<div th:fragment="navbar" class="mx-auto">
 | 
			
		||||
    <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 src="js/languageSelection.js"></script>
 | 
			
		||||
 | 
			
		||||
<script th:inline="javascript">
 | 
			
		||||
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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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();
 | 
			
		||||
	const currentVersion =  /*[[${@appVersion}]]*/ '';
 | 
			
		||||
	const noFavourites =  /*[[#{noFavourites}]]*/ '';
 | 
			
		||||
</script>
 | 
			
		||||
<script th:src="@{/js/githubVersion.js}"></script>
 | 
			
		||||
 | 
			
		||||
<link rel="stylesheet" href="css/navbar.css">
 | 
			
		||||
 | 
			
		||||
@ -263,48 +196,7 @@ function compareVersions(version1, version2) {
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
        <script th:inline="javascript">
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        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>
 | 
			
		||||
        
 | 
			
		||||
        <script src="js/favourites.js"></script>
 | 
			
		||||
    </nav>
 | 
			
		||||
    
 | 
			
		||||
	<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div>
 | 
			
		||||
@ -363,73 +255,7 @@ function compareVersions(version1, version2) {
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <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>
 | 
			
		||||
<script src="js/settings.js"></script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -27,72 +27,7 @@
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </form>
 | 
			
		||||
                        <link rel="stylesheet" href="css/merge.css">
 | 
			
		||||
                        <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>
 | 
			
		||||
                        <script src="js/merge.js"></script>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user