import { PDFDocument, PDFName } from 'pdf-lib'; import { createIcons, icons } from 'lucide'; import { loadPdfWithPasswordPrompt } from '../utils/password-prompt.js'; import { loadPdfDocument } from '../utils/load-pdf-document.js'; import { escapeHtml } from '../utils/helpers.js'; // State management const pageState: { pdfDoc: PDFDocument | null; file: File | null } = { pdfDoc: null, file: null, }; // UI helpers function showLoader(message: string = 'Processing...') { const loader = document.getElementById('loader-modal'); const loaderText = document.getElementById('loader-text'); if (loader) loader.classList.remove('hidden'); if (loaderText) loaderText.textContent = message; } function hideLoader() { const loader = document.getElementById('loader-modal'); if (loader) loader.classList.add('hidden'); } function showAlert( title: string, message: string, type: string = 'error', callback?: () => void ) { const modal = document.getElementById('alert-modal'); const alertTitle = document.getElementById('alert-title'); const alertMessage = document.getElementById('alert-message'); const okBtn = document.getElementById('alert-ok'); if (alertTitle) alertTitle.textContent = title; if (alertMessage) alertMessage.textContent = message; if (modal) modal.classList.remove('hidden'); if (okBtn) { const newOkBtn = okBtn.cloneNode(true) as HTMLElement; okBtn.replaceWith(newOkBtn); newOkBtn.addEventListener('click', () => { modal?.classList.add('hidden'); if (callback) callback(); }); } } function downloadFile(blob: Blob, filename: string) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } function updateFileDisplay() { const displayArea = document.getElementById('file-display-area'); if (!displayArea || !pageState.file || !pageState.pdfDoc) return; const fileSize = pageState.file.size < 1024 * 1024 ? `${(pageState.file.size / 1024).toFixed(1)} KB` : `${(pageState.file.size / 1024 / 1024).toFixed(2)} MB`; const pageCount = pageState.pdfDoc.getPageCount(); displayArea.innerHTML = `

${escapeHtml(pageState.file.name)}

${fileSize} • ${pageCount} page${pageCount !== 1 ? 's' : ''}

`; createIcons({ icons }); document .getElementById('remove-file') ?.addEventListener('click', () => resetState()); } function resetState() { pageState.pdfDoc = null; pageState.file = null; const displayArea = document.getElementById('file-display-area'); if (displayArea) displayArea.innerHTML = ''; document.getElementById('options-panel')?.classList.add('hidden'); const fileInput = document.getElementById('file-input') as HTMLInputElement; if (fileInput) fileInput.value = ''; } // File handling async function handleFileUpload(file: File) { if (!file || file.type !== 'application/pdf') { showAlert('Error', 'Please upload a valid PDF file.'); return; } try { const result = await loadPdfWithPasswordPrompt(file); if (!result) return; showLoader('Loading PDF...'); result.pdf.destroy(); pageState.pdfDoc = await loadPdfDocument(result.bytes); pageState.file = result.file; updateFileDisplay(); document.getElementById('options-panel')?.classList.remove('hidden'); } catch (error) { console.error(error); showAlert('Error', 'Failed to load PDF file.'); } finally { hideLoader(); } } // Process function async function processRemoveAnnotations() { if (!pageState.pdfDoc) { showAlert('Error', 'Please upload a PDF file first.'); return; } showLoader('Removing annotations...'); try { const pages = pageState.pdfDoc.getPages(); // Remove all annotations from all pages for (let i = 0; i < pages.length; i++) { const page = pages[i]; const annotRefs = page.node.Annots()?.asArray() || []; if (annotRefs.length > 0) { page.node.delete(PDFName.of('Annots')); } } const newPdfBytes = await pageState.pdfDoc.save(); downloadFile( new Blob([new Uint8Array(newPdfBytes)], { type: 'application/pdf' }), pageState.file?.name || 'document.pdf' ); showAlert('Success', 'Annotations removed successfully!', 'success', () => { resetState(); }); } catch (e) { console.error(e); showAlert('Error', 'Could not remove annotations.'); } finally { hideLoader(); } } // Initialize document.addEventListener('DOMContentLoaded', () => { const fileInput = document.getElementById('file-input') as HTMLInputElement; const dropZone = document.getElementById('drop-zone'); const processBtn = document.getElementById('process-btn'); const backBtn = document.getElementById('back-to-tools'); fileInput?.addEventListener('change', (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (file) handleFileUpload(file); }); dropZone?.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('border-indigo-500'); }); dropZone?.addEventListener('dragleave', () => { dropZone.classList.remove('border-indigo-500'); }); dropZone?.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('border-indigo-500'); const file = e.dataTransfer?.files[0]; if (file) handleFileUpload(file); }); processBtn?.addEventListener('click', processRemoveAnnotations); backBtn?.addEventListener('click', () => { window.location.href = '../../index.html'; }); });