import { showLoader, hideLoader, showAlert } from '../ui'; import { readFileAsArrayBuffer, downloadFile } from '../utils/helpers'; import { state } from '../state'; const worker = new Worker('/workers/add-attachments.worker.js'); let attachments: File[] = []; worker.onmessage = (e) => { const data = e.data; if (data.status === 'success' && data.modifiedPDF !== undefined) { hideLoader(); downloadFile( new Blob([new Uint8Array(data.modifiedPDF)], { type: 'application/pdf' }), `attached-${state.files[0].name}` ); showAlert('Success', `${attachments.length} file(s) attached successfully.`); clearAttachments(); } else if (data.status === 'error') { hideLoader(); showAlert('Error', data.message || 'Unknown error occurred.'); clearAttachments(); } }; worker.onerror = (error) => { hideLoader(); console.error('Worker error:', error); showAlert('Error', 'Worker error occurred. Check console for details.'); clearAttachments(); }; export async function addAttachments() { if (!state.files || state.files.length === 0) { showAlert('Error', 'Main PDF is not loaded.'); return; } if (attachments.length === 0) { showAlert('No Files', 'Please select at least one file to attach.'); return; } const attachmentLevel = ( document.querySelector('input[name="attachment-level"]:checked') as HTMLInputElement )?.value || 'document'; let pageRange: string = ''; if (attachmentLevel === 'page') { const pageRangeInput = document.getElementById('attachment-page-range') as HTMLInputElement; pageRange = pageRangeInput?.value?.trim() || ''; if (!pageRange) { showAlert('Error', 'Please specify a page range for page-level attachments.'); return; } } showLoader('Embedding files into PDF...'); try { const pdfFile = state.files[0]; const pdfBuffer = (await readFileAsArrayBuffer(pdfFile)) as ArrayBuffer; const attachmentBuffers: ArrayBuffer[] = []; const attachmentNames: string[] = []; for (let i = 0; i < attachments.length; i++) { const file = attachments[i]; showLoader(`Reading ${file.name} (${i + 1}/${attachments.length})...`); const fileBuffer = (await readFileAsArrayBuffer(file)) as ArrayBuffer; attachmentBuffers.push(fileBuffer); attachmentNames.push(file.name); } showLoader('Attaching files to PDF...'); const message = { command: 'add-attachments', pdfBuffer: pdfBuffer, attachmentBuffers: attachmentBuffers, attachmentNames: attachmentNames, attachmentLevel: attachmentLevel, pageRange: pageRange }; const transferables = [pdfBuffer, ...attachmentBuffers]; worker.postMessage(message, transferables); } catch (error: any) { console.error('Error attaching files:', error); hideLoader(); showAlert('Error', `Failed to attach files: ${error.message}`); clearAttachments(); } } function clearAttachments() { attachments = []; const fileListDiv = document.getElementById('attachment-file-list'); const attachmentInput = document.getElementById( 'attachment-files-input' ) as HTMLInputElement; const processBtn = document.getElementById( 'process-btn' ) as HTMLButtonElement; const attachmentLevelOptions = document.getElementById('attachment-level-options'); const pageRangeWrapper = document.getElementById('page-range-wrapper'); if (fileListDiv) fileListDiv.innerHTML = ''; if (attachmentInput) attachmentInput.value = ''; if (processBtn) { processBtn.disabled = true; processBtn.classList.add('hidden'); } if (attachmentLevelOptions) { attachmentLevelOptions.classList.add('hidden'); } if (pageRangeWrapper) { pageRangeWrapper.classList.add('hidden'); } const documentRadio = document.querySelector('input[name="attachment-level"][value="document"]') as HTMLInputElement; if (documentRadio) { documentRadio.checked = true; } } export function setupAddAttachmentsTool() { const optionsDiv = document.getElementById('attachment-options'); const attachmentInput = document.getElementById( 'attachment-files-input' ) as HTMLInputElement; const fileListDiv = document.getElementById('attachment-file-list'); const processBtn = document.getElementById( 'process-btn' ) as HTMLButtonElement; const attachmentLevelOptions = document.getElementById('attachment-level-options'); const pageRangeWrapper = document.getElementById('page-range-wrapper'); const totalPagesSpan = document.getElementById('attachment-total-pages'); if (!optionsDiv || !attachmentInput || !fileListDiv || !processBtn) { console.error('Attachment tool UI elements not found.'); return; } if (!state.files || state.files.length === 0) { console.error('No PDF file loaded for adding attachments.'); return; } optionsDiv.classList.remove('hidden'); if (totalPagesSpan && state.pdfDoc) { totalPagesSpan.textContent = state.pdfDoc.getPageCount().toString(); } if (attachmentInput.dataset.listenerAttached) return; attachmentInput.dataset.listenerAttached = 'true'; attachmentInput.addEventListener('change', (e) => { const files = (e.target as HTMLInputElement).files; if (files && files.length > 0) { attachments = Array.from(files); fileListDiv.innerHTML = ''; attachments.forEach((file) => { const div = document.createElement('div'); div.className = 'flex justify-between items-center p-2 bg-gray-800 rounded-md text-white'; const nameSpan = document.createElement('span'); nameSpan.className = 'truncate text-sm'; nameSpan.textContent = file.name; const sizeSpan = document.createElement('span'); sizeSpan.className = 'text-xs text-gray-400'; sizeSpan.textContent = `${Math.round(file.size / 1024)} KB`; div.appendChild(nameSpan); div.appendChild(sizeSpan); fileListDiv.appendChild(div); }); if (attachmentLevelOptions) { attachmentLevelOptions.classList.remove('hidden'); } processBtn.disabled = false; processBtn.classList.remove('hidden'); } else { clearAttachments(); } }); const attachmentLevelRadios = document.querySelectorAll('input[name="attachment-level"]'); attachmentLevelRadios.forEach((radio) => { radio.addEventListener('change', (e) => { const value = (e.target as HTMLInputElement).value; if (value === 'page' && pageRangeWrapper) { pageRangeWrapper.classList.remove('hidden'); } else if (pageRangeWrapper) { pageRangeWrapper.classList.add('hidden'); } }); }); processBtn.onclick = addAttachments; }