Turn the div adapters into injectable files so that each PdfContainer can be customized. And the adapters can be used in different PdfContainers as well.
207 lines
6.9 KiB
JavaScript
207 lines
6.9 KiB
JavaScript
class PdfContainer {
|
|
fileName;
|
|
pagesContainer;
|
|
pagesContainerWrapper;
|
|
pdfAdapters;
|
|
|
|
constructor(id, wrapperId, pdfAdapters) {
|
|
this.fileName = null;
|
|
this.pagesContainer = document.getElementById(id)
|
|
this.pagesContainerWrapper = document.getElementById(wrapperId);
|
|
this.movePageTo = this.movePageTo.bind(this);
|
|
this.addPdfs = this.addPdfs.bind(this);
|
|
this.rotateElement = this.rotateElement.bind(this);
|
|
this.rotateAll = this.rotateAll.bind(this);
|
|
this.exportPdf = this.exportPdf.bind(this);
|
|
|
|
this.pdfAdapters = pdfAdapters;
|
|
|
|
this.pdfAdapters.forEach(adapter => {
|
|
adapter.setActions({
|
|
movePageTo: this.movePageTo,
|
|
addPdfs: this.addPdfs,
|
|
rotateElement: this.rotateElement,
|
|
})
|
|
})
|
|
|
|
window.addPdfs = this.addPdfs;
|
|
window.exportPdf = this.exportPdf;
|
|
window.rotateAll = this.rotateAll;
|
|
}
|
|
|
|
movePageTo(startElement, endElement, scrollTo = false) {
|
|
const childArray = Array.from(this.pagesContainer.childNodes);
|
|
const startIndex = childArray.indexOf(startElement);
|
|
const endIndex = childArray.indexOf(endElement);
|
|
this.pagesContainer.removeChild(startElement);
|
|
if(!endElement) {
|
|
this.pagesContainer.append(startElement);
|
|
} else {
|
|
this.pagesContainer.insertBefore(startElement, endElement);
|
|
}
|
|
|
|
if(scrollTo) {
|
|
const { width } = startElement.getBoundingClientRect();
|
|
const vector = (endIndex !== -1 && startIndex > endIndex)
|
|
? 0-width
|
|
: width;
|
|
|
|
this.pagesContainerWrapper.scroll({
|
|
left: this.pagesContainerWrapper.scrollLeft + vector,
|
|
})
|
|
}
|
|
}
|
|
|
|
addPdfs(nextSiblingElement) {
|
|
var input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.multiple = true;
|
|
input.setAttribute("accept", "application/pdf");
|
|
|
|
input.onchange = async(e) => {
|
|
const files = e.target.files;
|
|
this.fileName = files[0].name;
|
|
for (var i=0; i < files.length; i++) {
|
|
this.addPdfFile(files[i], nextSiblingElement);
|
|
}
|
|
|
|
document.querySelectorAll(".enable-on-file").forEach(element => {
|
|
element.disabled = false;
|
|
});
|
|
}
|
|
|
|
input.click();
|
|
}
|
|
|
|
rotateElement(element, deg) {
|
|
var lastTransform = element.style.rotate;
|
|
if (!lastTransform) {
|
|
lastTransform = "0";
|
|
}
|
|
const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ''));
|
|
const newAngle = lastAngle + deg;
|
|
|
|
element.style.rotate = newAngle + "deg";
|
|
}
|
|
|
|
async addPdfFile(file, nextSiblingElement) {
|
|
const { renderer, pdfDocument } = await this.loadFile(file);
|
|
|
|
for (var i=0; i < renderer.pageCount; i++) {
|
|
const div = document.createElement('div');
|
|
|
|
div.classList.add("page-container");
|
|
|
|
var img = document.createElement('img');
|
|
img.classList.add('page-image')
|
|
const imageSrc = await renderer.renderPage(i)
|
|
img.src = imageSrc;
|
|
img.pageIdx = i;
|
|
img.rend = renderer;
|
|
img.doc = pdfDocument;
|
|
div.appendChild(img);
|
|
|
|
this.pdfAdapters.forEach((adapter) => {
|
|
adapter.adapt?.(div)
|
|
})
|
|
if (nextSiblingElement) {
|
|
this.pagesContainer.insertBefore(div, nextSiblingElement);
|
|
} else {
|
|
this.pagesContainer.appendChild(div);
|
|
}
|
|
}
|
|
}
|
|
|
|
async loadFile(file) {
|
|
var objectUrl = URL.createObjectURL(file);
|
|
var pdfDocument = await this.toPdfLib(objectUrl);
|
|
var renderer = await this.toRenderer(objectUrl);
|
|
return { renderer, pdfDocument };
|
|
}
|
|
|
|
async toRenderer(objectUrl) {
|
|
const pdf = await pdfjsLib.getDocument(objectUrl).promise;
|
|
return {
|
|
document: pdf,
|
|
pageCount: pdf.numPages,
|
|
renderPage: async function(pageIdx) {
|
|
const page = await this.document.getPage(pageIdx+1);
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
// set the canvas size to the size of the page
|
|
if (page.rotate == 90 || page.rotate == 270) {
|
|
canvas.width = page.view[3];
|
|
canvas.height = page.view[2];
|
|
} else {
|
|
canvas.width = page.view[2];
|
|
canvas.height = page.view[3];
|
|
}
|
|
|
|
// render the page onto the canvas
|
|
var renderContext = {
|
|
canvasContext: canvas.getContext("2d"),
|
|
viewport: page.getViewport({ scale: 1 })
|
|
};
|
|
|
|
await page.render(renderContext).promise;
|
|
return canvas.toDataURL();
|
|
}
|
|
};
|
|
}
|
|
|
|
async toPdfLib(objectUrl) {
|
|
const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer());
|
|
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes);
|
|
return pdfDoc;
|
|
}
|
|
|
|
|
|
|
|
rotateAll(deg) {
|
|
for (var i=0; i<this.pagesContainer.childNodes.length; i++) {
|
|
const img = this.pagesContainer.childNodes[i].querySelector("img");
|
|
if (!img) continue;
|
|
this.rotateElement(img, deg)
|
|
}
|
|
}
|
|
|
|
async exportPdf() {
|
|
const pdfDoc = await PDFLib.PDFDocument.create();
|
|
for (var i=0; i<this.pagesContainer.childNodes.length; i++) {
|
|
const img = this.pagesContainer.childNodes[i].querySelector("img");
|
|
if (!img) continue;
|
|
const pages = await pdfDoc.copyPages(img.doc, [img.pageIdx])
|
|
const page = pages[0];
|
|
|
|
const rotation = img.style.rotate;
|
|
if (rotation) {
|
|
const rotationAngle = parseInt(rotation.replace(/[^\d-]/g, ''));
|
|
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle))
|
|
}
|
|
|
|
pdfDoc.addPage(page);
|
|
}
|
|
const pdfBytes = await pdfDoc.save();
|
|
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' });
|
|
const url = URL.createObjectURL(pdfBlob);
|
|
const downloadOption = localStorage.getItem('downloadOption');
|
|
|
|
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
|
|
const downloadLink = document.createElement('a');
|
|
downloadLink.href = url;
|
|
downloadLink.download = this.fileName ? this.fileName : 'managed.pdf';
|
|
downloadLink.click();
|
|
}
|
|
}
|
|
}
|
|
|
|
export default PdfContainer;
|