update #5

Open
mdebray wants to merge 231 commits from update into main
5 changed files with 159 additions and 30 deletions
Showing only changes of commit 3c04486348 - Show all commits

View file

@ -127,6 +127,19 @@ label {
margin-bottom: 16px; margin-bottom: 16px;
} }
.page-container.split-before {
border-left: 1px dashed var(--md-sys-color-on-surface);
padding-left: -1px;
}
.page-container.split-before:first-child {
border-left: none;
}
.page-container:first-child .pdf-actions_split-file-button {
display: none;
}
/* Pushes the last item to the left */ /* Pushes the last item to the left */
.page-container:last-child { .page-container:last-child {
margin-right: auto; margin-right: auto;
@ -171,8 +184,9 @@ label {
.page-container:last-child:lang(nqo), .page-container:last-child:lang(nqo),
/* N'Ko */ /* N'Ko */
.page-container:last-child:lang(bqi) .page-container:last-child:lang(bqi)
/* Bakhtiari */ /* Bakhtiari */
{ {
margin-left: auto !important; margin-left: auto !important;
margin-right: 0 !important; margin-right: 0 !important;
} }

View file

@ -117,3 +117,12 @@ html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-butto
aspect-ratio: 1; aspect-ratio: 1;
border-radius: 100px; border-radius: 100px;
} }
.pdf-actions_split-file-button {
position: absolute;
top: 25%;
right: 50%;
translate: 0 -50%;
aspect-ratio: 1;
border-radius: 100px;
}

View file

@ -73,7 +73,12 @@ class PdfActionsManager {
this.addFiles(imgContainer); this.addFiles(imgContainer);
} }
setActions({ movePageTo, addFiles, rotateElement }) { splitFileButtonCallback(e) {
var imgContainer = this.getPageContainer(e.target);
imgContainer.classList.toggle("split-before");
}
setActions({ movePageTo, addPdfs, rotateElement }) {
this.movePageTo = movePageTo; this.movePageTo = movePageTo;
this.addFiles = addFiles; this.addFiles = addFiles;
this.rotateElement = rotateElement; this.rotateElement = rotateElement;
@ -84,6 +89,7 @@ class PdfActionsManager {
this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this); this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this);
this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this); this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this);
this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this); this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this);
this.splitFileButtonCallback = this.splitFileButtonCallback.bind(this);
} }
adapt(div) { adapt(div) {
@ -140,6 +146,12 @@ class PdfActionsManager {
insertFileButton.onclick = this.insertFileButtonCallback; insertFileButton.onclick = this.insertFileButtonCallback;
insertFileButtonContainer.appendChild(insertFileButton); insertFileButtonContainer.appendChild(insertFileButton);
const splitFileButton = document.createElement("button");
splitFileButton.classList.add("btn", "btn-primary", "pdf-actions_split-file-button");
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span>`;
splitFileButton.onclick = this.splitFileButtonCallback;
insertFileButtonContainer.appendChild(splitFileButton);
div.appendChild(insertFileButtonContainer); div.appendChild(insertFileButtonContainer);
// add this button to every element, but only show it on the last one :D // add this button to every element, but only show it on the last one :D

View file

@ -19,6 +19,9 @@ class PdfContainer {
this.setDownloadAttribute = this.setDownloadAttribute.bind(this); this.setDownloadAttribute = this.setDownloadAttribute.bind(this);
this.preventIllegalChars = this.preventIllegalChars.bind(this); this.preventIllegalChars = this.preventIllegalChars.bind(this);
this.addImageFile = this.addImageFile.bind(this); this.addImageFile = this.addImageFile.bind(this);
this.nameAndArchiveFiles = this.nameAndArchiveFiles.bind(this);
this.splitPDF = this.splitPDF.bind(this);
this.splitAll = this.splitAll.bind(this);
this.pdfAdapters = pdfAdapters; this.pdfAdapters = pdfAdapters;
@ -34,6 +37,7 @@ class PdfContainer {
window.addFiles = this.addFiles; window.addFiles = this.addFiles;
window.exportPdf = this.exportPdf; window.exportPdf = this.exportPdf;
window.rotateAll = this.rotateAll; window.rotateAll = this.rotateAll;
window.splitAll = this.splitAll;
const filenameInput = document.getElementById("filename-input"); const filenameInput = document.getElementById("filename-input");
const downloadBtn = document.getElementById("export-button"); const downloadBtn = document.getElementById("export-button");
@ -212,6 +216,61 @@ class PdfContainer {
} }
} }
splitAll() {
const allPages = this.pagesContainer.querySelectorAll(".page-container");
if (this.pagesContainer.querySelectorAll(".split-before").length > 0) {
allPages.forEach(page => {
page.classList.remove("split-before");
});
} else {
allPages.forEach(page => {
page.classList.add("split-before");
});
}
}
async splitPDF(baseDocBytes, splitters) {
const baseDocument = await PDFLib.PDFDocument.load(baseDocBytes);
const pageNum = baseDocument.getPages().length;
splitters.sort((a, b) => a - b);; // We'll sort the separator indexes just in case querySelectorAll does something funny.
splitters.push(pageNum); // We'll also add a faux separator at the end in order to get the pages after the last separator.
const splitDocuments = [];
for (const splitterPosition of splitters) {
const subDocument = await PDFLib.PDFDocument.create();
const splitterIndex = splitters.indexOf(splitterPosition);
let firstPage = splitterIndex === 0 ? 0 : splitters[splitterIndex - 1];
const pageIndices = Array.from({ length: splitterPosition - firstPage }, (value, key) => firstPage + key);
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
copiedPages.forEach(copiedPage => {
subDocument.addPage(copiedPage);
});
const subDocumentBytes = await subDocument.save();
splitDocuments.push(subDocumentBytes);
};
return splitDocuments;
}
async nameAndArchiveFiles(pdfBytesArray, baseNameString) {
const zip = new JSZip();
for (let i = 0; i < pdfBytesArray.length; i++) {
const documentBlob = new Blob([pdfBytesArray[i]], { type: "application/pdf" });
zip.file(baseNameString + "-" + (i + 1) + ".pdf", documentBlob);
}
return zip;
}
async exportPdf() { async exportPdf() {
const pdfDoc = await PDFLib.PDFDocument.create(); const pdfDoc = await PDFLib.PDFDocument.create();
const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements const pageContainers = this.pagesContainer.querySelectorAll(".page-container"); // Select all .page-container elements
@ -262,8 +321,6 @@ class PdfContainer {
} }
const pdfBytes = await pdfDoc.save(); const pdfBytes = await pdfDoc.save();
const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" }); const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
const url = URL.createObjectURL(pdfBlob);
const downloadOption = localStorage.getItem("downloadOption");
const filenameInput = document.getElementById("filename-input"); const filenameInput = document.getElementById("filename-input");
@ -280,28 +337,60 @@ class PdfContainer {
this.fileName = filenameInput.value; this.fileName = filenameInput.value;
} }
if (!filenameInput.value.includes(".pdf")) { const separators = this.pagesContainer.querySelectorAll(".split-before");
filenameInput.value = filenameInput.value + ".pdf"; if (separators.length !== 0) { // Split the pdf if there are separators.
this.fileName = filenameInput.value; const baseName = this.fileName ? this.fileName : "managed";
}
if (downloadOption === "sameWindow") { const pagesArray = Array.from(this.pagesContainer.children);
// Open the file in the same window const splitters = [];
window.location.href = url; separators.forEach(page => {
} else if (downloadOption === "newWindow") { const pageIndex = pagesArray.indexOf(page);
// Open the file in a new window if (pageIndex !== 0) {
window.open(url, "_blank"); splitters.push(pageIndex);
} else { }
// Download the file });
this.downloadLink = document.createElement("a");
this.downloadLink.id = "download-link"; const splitDocuments = await this.splitPDF(pdfBytes, splitters);
this.downloadLink.href = url; const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
// downloadLink.download = this.fileName; const self = this;
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf"); archivedDocuments.generateAsync({ type: "base64" }).then(function (base64) {
this.downloadLink.setAttribute("target", "_blank"); const url = "data:application/zip;base64," + base64;
this.downloadLink.onclick = this.setDownloadAttribute; self.downloadLink = document.createElement("a");
this.downloadLink.click(); self.downloadLink.href = url;
self.downloadLink.setAttribute("download", baseName + ".zip");
self.downloadLink.setAttribute("target", "_blank");
self.downloadLink.click();
});
} else { // Continue normally if there are no separators
const url = URL.createObjectURL(pdfBlob);
const downloadOption = localStorage.getItem("downloadOption");
if (!filenameInput.value.includes(".pdf")) {
filenameInput.value = filenameInput.value + ".pdf";
this.fileName = filenameInput.value;
}
if (downloadOption === "sameWindow") {
// Open the file in the same window
window.location.href = url;
} else if (downloadOption === "newWindow") {
// Open the file in a new window
window.open(url, "_blank");
} else {
// Download the file
this.downloadLink = document.createElement("a");
this.downloadLink.id = "download-link";
this.downloadLink.href = url;
// downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
// downloadLink.download = this.fileName;
this.downloadLink.setAttribute("download", this.fileName ? this.fileName : "managed.pdf");
this.downloadLink.setAttribute("target", "_blank");
this.downloadLink.onclick = this.setDownloadAttribute;
this.downloadLink.click();
}
} }
} }
@ -350,7 +439,7 @@ function detectImageType(uint8Array) {
// Check for TIFF signature (little-endian and big-endian) // Check for TIFF signature (little-endian and big-endian)
if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) || if ((uint8Array[0] === 73 && uint8Array[1] === 73 && uint8Array[2] === 42 && uint8Array[3] === 0) ||
(uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) { (uint8Array[0] === 77 && uint8Array[1] === 77 && uint8Array[2] === 0 && uint8Array[3] === 42)) {
return 'TIFF'; return 'TIFF';
} }

View file

@ -42,6 +42,11 @@
rotate_right rotate_right
</span> </span>
</button> </button>
<button class="btn btn-secondary enable-on-file" onclick="splitAll()" disabled>
<span class="material-symbols-rounded">
cut
</span>
</button>
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf()" disabled> <button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf()" disabled>
<span class="material-symbols-rounded"> <span class="material-symbols-rounded">
download download