diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/MergeController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/MergeController.java index 569c58f5ee5..b1132ec94f3 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/MergeController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/MergeController.java @@ -72,19 +72,29 @@ public PDDocument mergeDocuments(List documents) throws IOException // fileOrder is newline-delimited original filenames in the desired order. private static MultipartFile[] reorderFilesByProvidedOrder( MultipartFile[] files, String fileOrder) { - String[] desired = fileOrder.split("\n", -1); + // Split by various line endings and trim each entry + String[] desired = + stirling.software.common.util.RegexPatternUtils.getInstance() + .getNewlineSplitPattern() + .split(fileOrder); + List remaining = new ArrayList<>(Arrays.asList(files)); List ordered = new ArrayList<>(files.length); for (String name : desired) { - if (name == null || name.isEmpty()) continue; + name = name.trim(); + if (name.isEmpty()) { + log.debug("Skipping empty entry"); + continue; + } int idx = indexOfByOriginalFilename(remaining, name); if (idx >= 0) { ordered.add(remaining.remove(idx)); + } else { + log.debug("Filename from order list not found in uploaded files: {}", name); } } - // Append any files not explicitly listed, preserving their relative order ordered.addAll(remaining); return ordered.toArray(new MultipartFile[0]); } @@ -252,8 +262,10 @@ public ResponseEntity mergePdfs( // If front-end provided explicit visible order, honor it and override backend sorting if (fileOrder != null && !fileOrder.isBlank()) { + log.info("Reordering files based on fileOrder parameter"); files = reorderFilesByProvidedOrder(files, fileOrder); } else { + log.info("Sorting files based on sortType: {}", request.getSortType()); Arrays.sort( files, getSortComparator( diff --git a/app/core/src/main/resources/static/js/downloader.js b/app/core/src/main/resources/static/js/downloader.js index 9e074be5e1c..070fd90af11 100644 --- a/app/core/src/main/resources/static/js/downloader.js +++ b/app/core/src/main/resources/static/js/downloader.js @@ -74,6 +74,12 @@ showGameBtn.style.display = 'none'; } + // Log fileOrder for debugging + const fileOrderValue = formData.get('fileOrder'); + if (fileOrderValue) { + console.log('FormData fileOrder:', fileOrderValue); + } + // Remove empty file entries for (let [key, value] of formData.entries()) { if (value instanceof File && !value.name) { diff --git a/app/core/src/main/resources/static/js/merge.js b/app/core/src/main/resources/static/js/merge.js index 01d7d97d998..09a4fe2fc17 100644 --- a/app/core/src/main/resources/static/js/merge.js +++ b/app/core/src/main/resources/static/js/merge.js @@ -123,39 +123,38 @@ function attachMoveButtons() { } } -document.getElementById("sortByNameBtn").addEventListener("click", function () { +document.getElementById("sortByNameBtn").addEventListener("click", async function () { if (currentSort.field === "name" && !currentSort.descending) { currentSort.descending = true; - sortFiles((a, b) => b.name.localeCompare(a.name)); + await sortFiles((a, b) => b.name.localeCompare(a.name)); } else { currentSort.field = "name"; currentSort.descending = false; - sortFiles((a, b) => a.name.localeCompare(b.name)); + await sortFiles((a, b) => a.name.localeCompare(b.name)); } }); -document.getElementById("sortByDateBtn").addEventListener("click", function () { +document.getElementById("sortByDateBtn").addEventListener("click", async function () { if (currentSort.field === "lastModified" && !currentSort.descending) { currentSort.descending = true; - sortFiles((a, b) => b.lastModified - a.lastModified); + await sortFiles((a, b) => b.lastModified - a.lastModified); } else { currentSort.field = "lastModified"; currentSort.descending = false; - sortFiles((a, b) => a.lastModified - b.lastModified); + await sortFiles((a, b) => a.lastModified - b.lastModified); } }); -function sortFiles(comparator) { +async function sortFiles(comparator) { // Convert FileList to array and sort const sortedFilesArray = Array.from(document.getElementById("fileInput-input").files).sort(comparator); - // Refresh displayed list - displayFiles(sortedFilesArray); + // Refresh displayed list (wait for it to complete since it's async) + await displayFiles(sortedFilesArray); - // Update the files property - const dataTransfer = new DataTransfer(); - sortedFilesArray.forEach((file) => dataTransfer.items.add(file)); - document.getElementById("fileInput-input").files = dataTransfer.files; + // Update the file input and fileOrder based on the current display order + // This ensures consistency between display and file input + updateFiles(); } function updateFiles() { @@ -163,25 +162,36 @@ function updateFiles() { var liElements = document.querySelectorAll("#selectedFiles li"); const files = document.getElementById("fileInput-input").files; + console.log("updateFiles: found", liElements.length, "LI elements and", files.length, "files"); + for (var i = 0; i < liElements.length; i++) { var fileNameFromList = liElements[i].querySelector(".filename").innerText; - var fileFromFiles; + var found = false; for (var j = 0; j < files.length; j++) { var file = files[j]; if (file.name === fileNameFromList) { dataTransfer.items.add(file); + found = true; break; } } + if (!found) { + console.warn("updateFiles: Could not find file:", fileNameFromList); + } } + document.getElementById("fileInput-input").files = dataTransfer.files; + console.log("updateFiles: Updated file input with", dataTransfer.files.length, "files"); // Also populate hidden fileOrder to preserve visible order const order = Array.from(liElements) .map((li) => li.querySelector(".filename").innerText) .join("\n"); const orderInput = document.getElementById("fileOrder"); - if (orderInput) orderInput.value = order; + if (orderInput) { + orderInput.value = order; + console.log("Updated fileOrder:", order); + } } document.querySelector("#resetFileInputBtn").addEventListener("click", ()=>{