// static/js/script.js document.addEventListener('DOMContentLoaded', () => { // --- Element Selectors --- const jobListBody = document.getElementById('job-list-body'); const pdfForm = document.getElementById('pdf-form'); const pdfFileInput = document.getElementById('pdf-file-input'); const pdfFileName = document.getElementById('pdf-file-name'); const audioForm = document.getElementById('audio-form'); const audioFileInput = document.getElementById('audio-file-input'); const audioFileName = document.getElementById('audio-file-name'); const conversionForm = document.getElementById('conversion-form'); const conversionFileInput = document.getElementById('conversion-file-input'); const conversionFileName = document.getElementById('conversion-file-name'); const outputFormatSelect = document.getElementById('output-format-select'); // MODIFICATION: Store the Choices.js instance in a variable let conversionChoices = null; const activePolls = new Map(); // --- Main Event Listeners --- pdfFileInput.addEventListener('change', () => updateFileName(pdfFileInput, pdfFileName)); audioFileInput.addEventListener('change', () => updateFileName(audioFileInput, audioFileName)); conversionFileInput.addEventListener('change', () => updateFileName(conversionFileInput, conversionFileName)); pdfForm.addEventListener('submit', (e) => handleFormSubmit(e, '/ocr-pdf', pdfForm)); audioForm.addEventListener('submit', (e) => handleFormSubmit(e, '/transcribe-audio', audioForm)); conversionForm.addEventListener('submit', (e) => handleFormSubmit(e, '/convert-file', conversionForm)); jobListBody.addEventListener('click', (event) => { if (event.target.classList.contains('cancel-button')) { const jobId = event.target.dataset.jobId; handleCancelJob(jobId); } }); function initializeConversionSelector() { // MODIFICATION: Destroy the old instance if it exists before creating a new one if (conversionChoices) { conversionChoices.destroy(); } conversionChoices = new Choices(outputFormatSelect, { searchEnabled: true, itemSelectText: 'Select', shouldSort: false, placeholder: true, placeholderValue: 'Select a format...', }); const tools = window.APP_CONFIG.conversionTools || {}; const choicesArray = []; for (const toolKey in tools) { const tool = tools[toolKey]; const group = { label: tool.name, id: toolKey, disabled: false, choices: [] }; for (const formatKey in tool.formats) { group.choices.push({ value: `${toolKey}_${formatKey}`, label: `${formatKey.toUpperCase()} - ${tool.formats[formatKey]}` }); } choicesArray.push(group); } conversionChoices.setChoices(choicesArray, 'value', 'label', true); } // --- Helper Functions --- function updateFileName(input, nameDisplay) { const fileName = input.files.length > 0 ? input.files[0].name : 'No file chosen'; nameDisplay.textContent = fileName; nameDisplay.title = fileName; } async function handleFormSubmit(event, endpoint, form) { event.preventDefault(); const fileInput = form.querySelector('input[type="file"]'); const fileNameDisplay = form.querySelector('.file-name'); if (!fileInput.files[0]) return; const formData = new FormData(form); const submitButton = form.querySelector('button[type="submit"]'); submitButton.disabled = true; try { const response = await fetch(endpoint, { method: 'POST', body: formData }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.detail || `HTTP error! Status: ${response.status}`); } const result = await response.json(); const preliminaryJob = { id: result.job_id, status: 'pending', progress: 0, original_filename: fileInput.files[0].name, task_type: endpoint.includes('ocr') ? 'ocr' : (endpoint.includes('transcribe') ? 'transcription' : 'conversion'), created_at: new Date().toISOString() }; renderJobRow(preliminaryJob); startPolling(result.job_id); } catch (error) { console.error('Error submitting job:', error); alert(`Submission failed: ${error.message}`); } finally { form.reset(); if (fileNameDisplay) fileNameDisplay.textContent = 'No file chosen'; // MODIFICATION: Use the stored instance to correctly reset the dropdown // without causing an error. if (form.id === 'conversion-form' && conversionChoices) { conversionChoices.clearInput(); conversionChoices.setValue([]); // Clears the selected value } submitButton.disabled = false; } } async function handleCancelJob(jobId) { if (!confirm('Are you sure you want to cancel this job?')) return; try { const response = await fetch(`/job/${jobId}/cancel`, { method: 'POST' }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.detail || 'Failed to cancel job.'); } stopPolling(jobId); const row = document.getElementById(`job-${jobId}`); if (row) { const statusCell = row.querySelector('td[data-label="Status"] .cell-value'); const actionCell = row.querySelector('td[data-label="Action"] .cell-value'); if (statusCell) statusCell.innerHTML = `Cancelled`; if (actionCell) actionCell.innerHTML = `-`; } } catch (error) { console.error('Error cancelling job:', error); alert(`Error: ${error.message}`); } } async function loadInitialJobs() { try { const response = await fetch('/jobs'); if (!response.ok) throw new Error('Failed to fetch jobs.'); const jobs = await response.json(); jobListBody.innerHTML = ''; for (const job of jobs.reverse()) { renderJobRow(job); if (['pending', 'processing'].includes(job.status)) { startPolling(job.id); } } } catch (error) { console.error("Couldn't load job history:", error); jobListBody.innerHTML = '