document.addEventListener('DOMContentLoaded', function () { const { PDFDocument } = PDFLib; const dropArea = document.getElementById('drop-area'); const fileInput = document.getElementById('file-input'); const fileSelectBtn = document.getElementById('file-select-btn'); const pdfInfo = document.getElementById('pdf-info'); const pdfFilename = document.getElementById('pdf-filename'); const pdfPageCount = document.getElementById('pdf-page-count'); const pdfPaperCount = document.getElementById('pdf-paper-count'); const previewBtn = document.getElementById('preview-btn'); const exportSingleBtn = document.getElementById('export-single-btn'); const exportZipBtn = document.getElementById('export-zip-btn'); const bookletSizeInput = document.getElementById('booklet-size'); const firstBookletSizeInput = document.getElementById('first-booklet-size'); const blankPagesInput = document.getElementById('blank-pages-start'); let originalPdfBytes = null; let originalPageCount = 0; // Event Listeners ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropArea.addEventListener(eventName, preventDefaults, false); document.body.addEventListener(eventName, preventDefaults, false); }); ['dragenter', 'dragover'].forEach(eventName => dropArea.addEventListener(eventName, () => dropArea.classList.add('drag-over'), false)); ['dragleave', 'drop'].forEach(eventName => dropArea.addEventListener(eventName, () => dropArea.classList.remove('drag-over'), false)); dropArea.addEventListener('drop', handleDrop, false); fileSelectBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', handleFileSelect, false); previewBtn.addEventListener('click', updatePreview); exportSingleBtn.addEventListener('click', exportAsSinglePdf); exportZipBtn.addEventListener('click', exportAsZip); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } function handleDrop(e) { handleFiles(e.dataTransfer.files); } function handleFileSelect(e) { handleFiles(e.target.files); } async function handleFiles(files) { if (files.length > 0) { const file = files[0]; if (file.type === 'application/pdf') { pdfFilename.textContent = file.name; dropArea.classList.add('loaded'); dropArea.querySelector('p').textContent = 'Drag & drop or click to select a different PDF.'; const fileReader = new FileReader(); fileReader.onload = async function() { originalPdfBytes = new Uint8Array(this.result); try { const pdfDoc = await PDFDocument.load(originalPdfBytes); originalPageCount = pdfDoc.getPageCount(); pdfPageCount.textContent = originalPageCount; const paperCount = Math.ceil(originalPageCount / 4); pdfPaperCount.textContent = paperCount; pdfInfo.classList.remove('d-none'); document.getElementById('recommendation-section').classList.remove('d-none'); previewBtn.disabled = false; exportSingleBtn.disabled = false; exportZipBtn.disabled = false; updateRecommendationTable(); updatePreview(); // Auto-update preview on new file } catch (e) { console.error(e); alert('Failed to load PDF. The file may be corrupt.'); } }; fileReader.readAsArrayBuffer(file); } else { alert('Please select a PDF file.'); } } } function padAndImposeBooklet(bookletPages) { const paddedBookletSize = Math.ceil(bookletPages.length / 4) * 4; while (bookletPages.length < paddedBookletSize) { bookletPages.push({ type: 'blank' }); } return imposeBooklet(bookletPages); } function calculateImposition() { const bookletSize = parseInt(bookletSizeInput.value, 10); let firstBookletSize = parseInt(firstBookletSizeInput.value, 10) || bookletSize; const blankPagesAtStart = parseInt(blankPagesInput.value, 10) || 0; if (bookletSize % 4 !== 0 || (firstBookletSize && firstBookletSize % 4 !== 0)) { alert('Booklet sizes must be a multiple of 4.'); return null; } const totalPages = originalPageCount + blankPagesAtStart; let sourcePages = []; for (let i = 0; i < blankPagesAtStart; i++) sourcePages.push({ type: 'blank' }); for (let i = 1; i <= originalPageCount; i++) sourcePages.push({ type: 'pdf', pageNum: i }); let booklets = []; // First booklet let firstBookletActualSize = (firstBookletSize > 0 && totalPages > 0) ? firstBookletSize : bookletSize; if (totalPages < firstBookletSize) { firstBookletActualSize = Math.ceil(totalPages / 4) * 4; } const firstBookletPages = sourcePages.splice(0, firstBookletActualSize); booklets.push(padAndImposeBooklet(firstBookletPages)); // Remaining booklets while (sourcePages.length > 0) { const bookletPages = sourcePages.splice(0, bookletSize); booklets.push(padAndImposeBooklet(bookletPages)); } return booklets; } function imposeBooklet(bookletPages) { const size = bookletPages.length; const imposed = []; for (let i = 0; i < size / 2; i += 2) { imposed.push(bookletPages[size - 1 - i]); imposed.push(bookletPages[i]); imposed.push(bookletPages[i + 1]); imposed.push(bookletPages[size - 2 - i]); } return imposed; } function updatePreview() { const booklets = calculateImposition(); if (!booklets) return; const previewArea = document.getElementById('imposition-preview'); let html = ''; booklets.forEach((booklet, index) => { html += `