Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

194 lines
6.4 KiB
JavaScript
Raw Normal View History

2023-08-17 22:03:36 +01:00
let currentSort = {
field: null,
descending: false,
2023-08-17 22:03:36 +01:00
};
Fix: input file overwrite in merge (#2335) * Fix input files being overwritten by newly uploaded files - Fix a bug that caused existing selected/uploaded files to be overwritten when a new input file is uploaded through input element. - Add source property to change event to differentiate between uploaded files using input element and drag/drop uploads to avoid processing drag/drop files more than once, thus avoiding file duplication (file duplication resulting from copying drop/drop files to input files on each 'change' event). * Dispatch and use file-input-change instead of change event for merging - Dispatch "file-input-change" event after each "change" event in file upload, to notify other functions/components relying on the files provided by the \<input\> element. - Use "file-input-change" instead of "change" event to display the latest version of uploaded files. # FAQ: - Why use "file-input-change" instead of "change" in merge.js? = "change" event is automatically triggered when a file is uploaded through \<input\> element which would replace all the existing selected/uploaded files including the drag/drop files. ## Example: Let's say that the user wants to upload/select the x.pdf, y.pdf and z.pdf all together: - user selects "x.pdf" -> file selected successfully. = selected files: x.pdf - user drags and drops "y.pdf" -> file dropped successfully = selected files: x.pdf, y.pdf - user selects again using \<input\> "z.pdf" -> file selected succesfully overwriting selected files. = selected files: z.pdf
2024-11-26 22:41:08 +02:00
document.getElementById("fileInput-input").addEventListener("file-input-change", function () {
var files = this.files;
displayFiles(files);
2023-08-17 22:03:36 +01:00
});
/**
* @param {FileList} files
*/
async function displayFiles(files) {
const list = document.getElementById("selectedFiles");
2023-08-17 22:03:36 +01:00
while (list.firstChild) {
list.removeChild(list.firstChild);
}
for (let i = 0; i < files.length; i++) {
const pageCount = await getPDFPageCount(files[i]);
const pageLabel = pageCount === 1 ? pageTranslation : pagesTranslation;
2024-11-15 13:21:23 -07:00
// Create list item
const item = document.createElement("li");
item.className = "list-group-item";
// Create filename div and set textContent to sanitize
const fileNameDiv = document.createElement("div");
fileNameDiv.className = "filename";
Fix drag and drop area for file choosers by adding separate ones (#2368) * Add separate drag and drop area for file choosers - Add separate drag and drop area for file choosers ### Why? Previously, when there were multiple file choosers in the same page, if you attempted to drag and drop any files, they would be added to both file choosers as it was designed at first to handle 1 file chooser present, now that we have multiple ones, it is necessary to adapt our design to match the changing functionality. ### Can you not preserve the old overlay when there's only one file chooser present? Yes, we can, but imagine as a user, you try to drag and drop a file in one page and the fields turn into drag and drop areas then you go to another page and try to drag and drop again but you encounter the old overlay instead, as a user you might get confused and ask yourself "What changed?" or if a user is telling another user the steps to drag and drop files and he didn't know about this case, then it would still be confusing, thus consistency is preferred in this case. * Update file chooser UI * Add support for listing and removing selected files and their file icons - Selected files are listed below the file chooser in a selected files container. - Users can now remove uploaded/selected files. - Hide selected files container/box unless there are files selected/uploaded. - Add separate overlay for each drag & drop area. ## FAQ: - Why did you assign a unique id to each file? isn't the filename enough? = Because a user might upload multiple files with the same name, if the user wanted to remove one of them, how would we differentiate between them? we won't be able to unless we assign an identifier, you might argue "we remove based on the filename and size", then what if the user uploaded the same file more than once (intentionally), then we would accidentally remove all the files even though that is not what the user wanted, so going with unique ID approach would prevent this issue/problem from occurring in the first place. * Rename remove-file css class to remove-selected-file - Rename remove-file css class to remove-selected-file to avoid css conflict with remove-file in merge.css * Use input element to dispatch event on file removal Use the correct element to dispatch "file-input-change" (input element is the correct one). * Adapt file chooser UI to themes - Adapt file chooser UI to themes by adjusting their font colors and background colors. - Make text more visible in overlay by increasing the font size by 0.1rem and setting font weight to 550. * Remove extra overlay border - Removing overlay's border as it is unnecessary and only causing a double border issue on the file input container. * Remove Browse button, highlight file chooser and make it clickable - Remove browse button. - Make the entire file chooser container clickable. - Add glowing effect on hover for file chooser. - Change color of file chooser on hover. * Replace crypto.randomUUID() with UUID.uuidv4() - Replace crypto.randomUUID() with UUID.uuidv4() as crypto.randomUUID() is only supported in secured contexts such as localhost 127.0.0.1 and over HTTPS * Fix merge file removal not being reflected in file chooser - Files removed from the list in merge page would now be reflected in the file chooser's container. * Make inputElement optional in removeFileById - Make inputElement optional in removeFileById, this way we could control changing inputElements files. * Add translation support to file chooser --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-12-02 20:10:12 +02:00
fileNameDiv.setAttribute("data-file-id", files[i].uniqueId);
fileNameDiv.textContent = files[i].name;
// Create page info div and set textContent to sanitize
const pageInfoDiv = document.createElement("div");
pageInfoDiv.className = "page-info";
const pageCountSpan = document.createElement("span");
pageCountSpan.className = "page-count";
pageCountSpan.textContent = `${pageCount} ${pageLabel}`;
pageInfoDiv.appendChild(pageCountSpan);
// Create arrows div with buttons
const arrowsDiv = document.createElement("div");
arrowsDiv.className = "arrows d-flex";
const moveUpButton = document.createElement("button");
moveUpButton.className = "btn btn-secondary move-up";
moveUpButton.innerHTML = "<span>&uarr;</span>";
const moveDownButton = document.createElement("button");
moveDownButton.className = "btn btn-secondary move-down";
moveDownButton.innerHTML = "<span>&darr;</span>";
const removeButton = document.createElement("button");
removeButton.className = "btn btn-danger remove-file";
removeButton.innerHTML = "<span>&times;</span>";
arrowsDiv.append(moveUpButton, moveDownButton, removeButton);
// Append elements to item and then to list
const itemContainer = document.createElement("div");
itemContainer.className = "d-flex justify-content-between align-items-center w-100";
itemContainer.append(fileNameDiv, pageInfoDiv, arrowsDiv);
item.appendChild(itemContainer);
list.appendChild(item);
}
attachMoveButtons();
2023-08-17 22:03:36 +01:00
}
async function getPDFPageCount(file) {
const blobUrl = URL.createObjectURL(file);
const pdf = await pdfjsLib.getDocument(blobUrl).promise;
URL.revokeObjectURL(blobUrl);
return pdf.numPages;
}
2023-08-17 22:03:36 +01:00
function attachMoveButtons() {
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();
}
});
}
2023-08-17 22:03:36 +01:00
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();
}
});
}
2023-12-30 16:42:41 +05:30
var removeButtons = document.querySelectorAll(".remove-file");
for (var i = 0; i < removeButtons.length; i++) {
removeButtons[i].addEventListener("click", function (event) {
event.preventDefault();
var parent = this.closest(".list-group-item");
//Get name of removed file
Fix drag and drop area for file choosers by adding separate ones (#2368) * Add separate drag and drop area for file choosers - Add separate drag and drop area for file choosers ### Why? Previously, when there were multiple file choosers in the same page, if you attempted to drag and drop any files, they would be added to both file choosers as it was designed at first to handle 1 file chooser present, now that we have multiple ones, it is necessary to adapt our design to match the changing functionality. ### Can you not preserve the old overlay when there's only one file chooser present? Yes, we can, but imagine as a user, you try to drag and drop a file in one page and the fields turn into drag and drop areas then you go to another page and try to drag and drop again but you encounter the old overlay instead, as a user you might get confused and ask yourself "What changed?" or if a user is telling another user the steps to drag and drop files and he didn't know about this case, then it would still be confusing, thus consistency is preferred in this case. * Update file chooser UI * Add support for listing and removing selected files and their file icons - Selected files are listed below the file chooser in a selected files container. - Users can now remove uploaded/selected files. - Hide selected files container/box unless there are files selected/uploaded. - Add separate overlay for each drag & drop area. ## FAQ: - Why did you assign a unique id to each file? isn't the filename enough? = Because a user might upload multiple files with the same name, if the user wanted to remove one of them, how would we differentiate between them? we won't be able to unless we assign an identifier, you might argue "we remove based on the filename and size", then what if the user uploaded the same file more than once (intentionally), then we would accidentally remove all the files even though that is not what the user wanted, so going with unique ID approach would prevent this issue/problem from occurring in the first place. * Rename remove-file css class to remove-selected-file - Rename remove-file css class to remove-selected-file to avoid css conflict with remove-file in merge.css * Use input element to dispatch event on file removal Use the correct element to dispatch "file-input-change" (input element is the correct one). * Adapt file chooser UI to themes - Adapt file chooser UI to themes by adjusting their font colors and background colors. - Make text more visible in overlay by increasing the font size by 0.1rem and setting font weight to 550. * Remove extra overlay border - Removing overlay's border as it is unnecessary and only causing a double border issue on the file input container. * Remove Browse button, highlight file chooser and make it clickable - Remove browse button. - Make the entire file chooser container clickable. - Add glowing effect on hover for file chooser. - Change color of file chooser on hover. * Replace crypto.randomUUID() with UUID.uuidv4() - Replace crypto.randomUUID() with UUID.uuidv4() as crypto.randomUUID() is only supported in secured contexts such as localhost 127.0.0.1 and over HTTPS * Fix merge file removal not being reflected in file chooser - Files removed from the list in merge page would now be reflected in the file chooser's container. * Make inputElement optional in removeFileById - Make inputElement optional in removeFileById, this way we could control changing inputElements files. * Add translation support to file chooser --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-12-02 20:10:12 +02:00
let filenameNode = parent.querySelector(".filename");
var fileName = filenameNode.innerText;
const fileId = filenameNode.getAttribute("data-file-id");
parent.remove();
updateFiles();
//Dispatch a custom event with the name of the removed file
Fix drag and drop area for file choosers by adding separate ones (#2368) * Add separate drag and drop area for file choosers - Add separate drag and drop area for file choosers ### Why? Previously, when there were multiple file choosers in the same page, if you attempted to drag and drop any files, they would be added to both file choosers as it was designed at first to handle 1 file chooser present, now that we have multiple ones, it is necessary to adapt our design to match the changing functionality. ### Can you not preserve the old overlay when there's only one file chooser present? Yes, we can, but imagine as a user, you try to drag and drop a file in one page and the fields turn into drag and drop areas then you go to another page and try to drag and drop again but you encounter the old overlay instead, as a user you might get confused and ask yourself "What changed?" or if a user is telling another user the steps to drag and drop files and he didn't know about this case, then it would still be confusing, thus consistency is preferred in this case. * Update file chooser UI * Add support for listing and removing selected files and their file icons - Selected files are listed below the file chooser in a selected files container. - Users can now remove uploaded/selected files. - Hide selected files container/box unless there are files selected/uploaded. - Add separate overlay for each drag & drop area. ## FAQ: - Why did you assign a unique id to each file? isn't the filename enough? = Because a user might upload multiple files with the same name, if the user wanted to remove one of them, how would we differentiate between them? we won't be able to unless we assign an identifier, you might argue "we remove based on the filename and size", then what if the user uploaded the same file more than once (intentionally), then we would accidentally remove all the files even though that is not what the user wanted, so going with unique ID approach would prevent this issue/problem from occurring in the first place. * Rename remove-file css class to remove-selected-file - Rename remove-file css class to remove-selected-file to avoid css conflict with remove-file in merge.css * Use input element to dispatch event on file removal Use the correct element to dispatch "file-input-change" (input element is the correct one). * Adapt file chooser UI to themes - Adapt file chooser UI to themes by adjusting their font colors and background colors. - Make text more visible in overlay by increasing the font size by 0.1rem and setting font weight to 550. * Remove extra overlay border - Removing overlay's border as it is unnecessary and only causing a double border issue on the file input container. * Remove Browse button, highlight file chooser and make it clickable - Remove browse button. - Make the entire file chooser container clickable. - Add glowing effect on hover for file chooser. - Change color of file chooser on hover. * Replace crypto.randomUUID() with UUID.uuidv4() - Replace crypto.randomUUID() with UUID.uuidv4() as crypto.randomUUID() is only supported in secured contexts such as localhost 127.0.0.1 and over HTTPS * Fix merge file removal not being reflected in file chooser - Files removed from the list in merge page would now be reflected in the file chooser's container. * Make inputElement optional in removeFileById - Make inputElement optional in removeFileById, this way we could control changing inputElements files. * Add translation support to file chooser --------- Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2024-12-02 20:10:12 +02:00
var event = new CustomEvent("fileRemoved", { detail: fileId });
document.dispatchEvent(event);
});
}
2023-08-17 22:03:36 +01:00
}
document.getElementById("sortByNameBtn").addEventListener("click", function () {
if (currentSort.field === "name" && !currentSort.descending) {
currentSort.descending = true;
sortFiles((a, b) => b.name.localeCompare(a.name));
} else {
currentSort.field = "name";
currentSort.descending = false;
sortFiles((a, b) => a.name.localeCompare(b.name));
}
2023-08-17 22:03:36 +01:00
});
document.getElementById("sortByDateBtn").addEventListener("click", function () {
if (currentSort.field === "lastModified" && !currentSort.descending) {
currentSort.descending = true;
sortFiles((a, b) => b.lastModified - a.lastModified);
} else {
currentSort.field = "lastModified";
currentSort.descending = false;
sortFiles((a, b) => a.lastModified - b.lastModified);
}
2023-08-17 22:03:36 +01:00
});
function sortFiles(comparator) {
// Convert FileList to array and sort
const sortedFilesArray = Array.from(document.getElementById("fileInput-input").files).sort(comparator);
2023-08-17 22:03:36 +01:00
// Refresh displayed list
displayFiles(sortedFilesArray);
2023-08-17 22:03:36 +01:00
// Update the files property
const dataTransfer = new DataTransfer();
sortedFilesArray.forEach((file) => dataTransfer.items.add(file));
document.getElementById("fileInput-input").files = dataTransfer.files;
2023-08-17 22:03:36 +01:00
}
function updateFiles() {
var dataTransfer = new DataTransfer();
var liElements = document.querySelectorAll("#selectedFiles li");
const files = document.getElementById("fileInput-input").files;
2023-08-17 22:03:36 +01:00
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;
}
2023-08-17 22:03:36 +01:00
}
}
document.getElementById("fileInput-input").files = dataTransfer.files;
2023-08-17 22:03:36 +01:00
}
2024-11-15 13:21:23 -07:00
document.querySelector("#resetFileInputBtn").addEventListener("click", ()=>{
let formElement = document.querySelector("#fileInput-input");
formElement.value = '';
clearLiElements();
updateFiles();
});
function clearLiElements(){
let listGroupItemNodeList = document.querySelectorAll(".list-group-item");
for (let i = 0; i < listGroupItemNodeList.length; i++) {
listGroupItemNodeList[i].remove();
};
}