new file: README_INSTALL.md new file: requirements.txt new file: static/css/style.css new file: static/js/images-to-pdf.js new file: static/js/main.js new file: static/js/pdf-tools.js new file: templates/pdf_tools.html
342 lines
9.9 KiB
JavaScript
342 lines
9.9 KiB
JavaScript
// PDF Tools - JavaScript Functionality
|
|
|
|
let pdfToolsFiles = [];
|
|
let mergeSortable = null;
|
|
let currentPdfFile = null;
|
|
|
|
// DOM elements
|
|
let mergeUploadArea, mergeFileInput, mergeFileList, mergeFilesContainer, mergePdfsBtn;
|
|
let splitUploadArea, splitFileInput, splitFileInfo, convertToImagesBtn;
|
|
let mergeResult, splitResult, mergeDownloadLink, splitDownloadLink;
|
|
let processingModal, errorArea, errorMessage;
|
|
|
|
// Initialize when page loads
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeDOMElements();
|
|
setupEventListeners();
|
|
setupDragAndDrop();
|
|
});
|
|
|
|
function initializeDOMElements() {
|
|
// Merge elements
|
|
mergeUploadArea = document.getElementById('merge-upload-area');
|
|
mergeFileInput = document.getElementById('merge-file-input');
|
|
mergeFileList = document.getElementById('merge-file-list');
|
|
mergeFilesContainer = document.getElementById('merge-files-container');
|
|
mergePdfsBtn = document.getElementById('merge-pdfs-btn');
|
|
mergeResult = document.getElementById('merge-result');
|
|
mergeDownloadLink = document.getElementById('merge-download-link');
|
|
|
|
// Split elements
|
|
splitUploadArea = document.getElementById('split-upload-area');
|
|
splitFileInput = document.getElementById('split-file-input');
|
|
splitFileInfo = document.getElementById('split-file-info');
|
|
convertToImagesBtn = document.getElementById('convert-to-images-btn');
|
|
splitResult = document.getElementById('split-result');
|
|
splitDownloadLink = document.getElementById('split-download-link');
|
|
|
|
// Common elements
|
|
processingModal = new bootstrap.Modal(document.getElementById('processing-modal'));
|
|
errorArea = document.getElementById('pdf-tools-error');
|
|
errorMessage = document.getElementById('pdf-tools-error-message');
|
|
}
|
|
|
|
function setupEventListeners() {
|
|
// Merge PDF events
|
|
mergeFileInput.addEventListener('change', function(e) {
|
|
handleMergeFiles(Array.from(e.target.files));
|
|
});
|
|
|
|
mergeUploadArea.addEventListener('click', function() {
|
|
mergeFileInput.click();
|
|
});
|
|
|
|
mergePdfsBtn.addEventListener('click', mergePdfs);
|
|
|
|
// Split PDF events
|
|
splitFileInput.addEventListener('change', function(e) {
|
|
if (e.target.files.length > 0) {
|
|
handleSplitFile(e.target.files[0]);
|
|
}
|
|
});
|
|
|
|
splitUploadArea.addEventListener('click', function() {
|
|
splitFileInput.click();
|
|
});
|
|
|
|
convertToImagesBtn.addEventListener('click', convertPdfToImages);
|
|
|
|
// Tab change events
|
|
document.querySelectorAll('[data-bs-toggle="pill"]').forEach(tab => {
|
|
tab.addEventListener('shown.bs.tab', function(e) {
|
|
hideAllResults();
|
|
});
|
|
});
|
|
}
|
|
|
|
function setupDragAndDrop() {
|
|
// Merge area drag and drop
|
|
setupDragAndDrop(mergeUploadArea, handleMergeFiles);
|
|
|
|
// Split area drag and drop
|
|
setupDragAndDrop(splitUploadArea, function(files) {
|
|
if (files.length > 0) {
|
|
handleSplitFile(files[0]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Merge PDF functions
|
|
async function handleMergeFiles(files) {
|
|
hideAllResults();
|
|
|
|
if (!files || files.length === 0) {
|
|
showError('Keine Dateien ausgewählt.');
|
|
return;
|
|
}
|
|
|
|
// Filter PDF files
|
|
const pdfFiles = files.filter(file => file.type === 'application/pdf');
|
|
|
|
if (pdfFiles.length === 0) {
|
|
showError('Keine PDF-Dateien gefunden.');
|
|
return;
|
|
}
|
|
|
|
if (pdfFiles.length < 2) {
|
|
showError('Mindestens 2 PDF-Dateien erforderlich.');
|
|
return;
|
|
}
|
|
|
|
// Upload files one by one
|
|
pdfToolsFiles = [];
|
|
|
|
for (const file of pdfFiles) {
|
|
try {
|
|
const response = await uploadSinglePdf(file);
|
|
if (response.success) {
|
|
pdfToolsFiles.push(response);
|
|
}
|
|
} catch (error) {
|
|
showError(`Fehler beim Upload von ${file.name}: ${error.message}`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
displayMergeFiles();
|
|
showNotification(`${pdfToolsFiles.length} PDF-Dateien erfolgreich hochgeladen.`, 'success');
|
|
}
|
|
|
|
async function uploadSinglePdf(file) {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
const response = await fetch('/api/upload-pdf', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
return await response.json();
|
|
}
|
|
|
|
function displayMergeFiles() {
|
|
mergeFilesContainer.innerHTML = '';
|
|
|
|
pdfToolsFiles.forEach((file, index) => {
|
|
const fileItem = createMergeFileItem(file, index);
|
|
mergeFilesContainer.appendChild(fileItem);
|
|
});
|
|
|
|
mergeFileList.style.display = 'block';
|
|
mergePdfsBtn.disabled = pdfToolsFiles.length < 2;
|
|
|
|
// Setup sortable
|
|
setupMergeSortable();
|
|
}
|
|
|
|
function createMergeFileItem(file, index) {
|
|
const div = document.createElement('div');
|
|
div.className = 'list-group-item';
|
|
div.dataset.index = index;
|
|
|
|
div.innerHTML = `
|
|
<div class="d-flex align-items-center">
|
|
<div class="file-icon me-3">
|
|
<i class="fas fa-file-pdf text-danger fa-2x"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<div class="file-name fw-bold">${file.original_name}</div>
|
|
<div class="file-details text-muted">
|
|
${file.page_count} Seiten • ${formatFileSize(file.size)}
|
|
</div>
|
|
</div>
|
|
<div class="file-actions">
|
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeMergeFile(${index})">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
return div;
|
|
}
|
|
|
|
function setupMergeSortable() {
|
|
if (mergeSortable) {
|
|
mergeSortable.destroy();
|
|
}
|
|
|
|
mergeSortable = setupSortable(mergeFilesContainer, function(evt) {
|
|
const item = pdfToolsFiles.splice(evt.oldIndex, 1)[0];
|
|
pdfToolsFiles.splice(evt.newIndex, 0, item);
|
|
displayMergeFiles();
|
|
});
|
|
}
|
|
|
|
function removeMergeFile(index) {
|
|
pdfToolsFiles.splice(index, 1);
|
|
|
|
if (pdfToolsFiles.length === 0) {
|
|
mergeFileList.style.display = 'none';
|
|
mergePdfsBtn.disabled = true;
|
|
} else {
|
|
displayMergeFiles();
|
|
}
|
|
|
|
showNotification('PDF-Datei entfernt.', 'info');
|
|
}
|
|
|
|
async function mergePdfs() {
|
|
if (pdfToolsFiles.length < 2) {
|
|
showError('Mindestens 2 PDF-Dateien erforderlich.');
|
|
return;
|
|
}
|
|
|
|
hideAllResults();
|
|
processingModal.show();
|
|
|
|
try {
|
|
const filenames = pdfToolsFiles.map(file => file.filename);
|
|
|
|
const response = await makeRequest('/api/merge-pdfs', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ filenames })
|
|
});
|
|
|
|
if (response.success) {
|
|
showMergeResult(response.filename, response.message);
|
|
showNotification(response.message, 'success');
|
|
} else {
|
|
throw new Error(response.error || 'Zusammenführung fehlgeschlagen');
|
|
}
|
|
} catch (error) {
|
|
showError(`Fehler beim Zusammenführen: ${error.message}`);
|
|
} finally {
|
|
processingModal.hide();
|
|
}
|
|
}
|
|
|
|
function showMergeResult(filename, message) {
|
|
mergeResult.style.display = 'block';
|
|
mergeDownloadLink.href = `/download/${filename}`;
|
|
|
|
if (message) {
|
|
mergeResult.querySelector('p').textContent = message;
|
|
}
|
|
}
|
|
|
|
// Split PDF functions
|
|
async function handleSplitFile(file) {
|
|
hideAllResults();
|
|
|
|
if (!file) {
|
|
showError('Keine Datei ausgewählt.');
|
|
return;
|
|
}
|
|
|
|
if (file.type !== 'application/pdf') {
|
|
showError('Nur PDF-Dateien sind erlaubt.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await uploadSinglePdf(file);
|
|
|
|
if (response.success) {
|
|
currentPdfFile = response;
|
|
displaySplitFile();
|
|
showNotification('PDF-Datei erfolgreich hochgeladen.', 'success');
|
|
} else {
|
|
throw new Error(response.error || 'Upload fehlgeschlagen');
|
|
}
|
|
} catch (error) {
|
|
showError(`Upload-Fehler: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function displaySplitFile() {
|
|
document.getElementById('split-filename').textContent = currentPdfFile.original_name;
|
|
document.getElementById('split-file-details').textContent =
|
|
`${currentPdfFile.page_count} Seiten • ${formatFileSize(currentPdfFile.size)}`;
|
|
|
|
splitFileInfo.style.display = 'block';
|
|
}
|
|
|
|
async function convertPdfToImages() {
|
|
if (!currentPdfFile) {
|
|
showError('Keine PDF-Datei ausgewählt.');
|
|
return;
|
|
}
|
|
|
|
hideAllResults();
|
|
processingModal.show();
|
|
|
|
try {
|
|
const response = await makeRequest('/api/pdf-to-images', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ filename: currentPdfFile.filename })
|
|
});
|
|
|
|
if (response.success) {
|
|
showSplitResult(response.filename, response.message);
|
|
showNotification(response.message, 'success');
|
|
} else {
|
|
throw new Error(response.error || 'Konvertierung fehlgeschlagen');
|
|
}
|
|
} catch (error) {
|
|
showError(`Konvertierungs-Fehler: ${error.message}`);
|
|
} finally {
|
|
processingModal.hide();
|
|
}
|
|
}
|
|
|
|
function showSplitResult(filename, message) {
|
|
splitResult.style.display = 'block';
|
|
splitDownloadLink.href = `/download/${filename}`;
|
|
|
|
if (message) {
|
|
splitResult.querySelector('p').textContent = message;
|
|
}
|
|
}
|
|
|
|
// Utility functions
|
|
function hideAllResults() {
|
|
if (mergeResult) mergeResult.style.display = 'none';
|
|
if (splitResult) splitResult.style.display = 'none';
|
|
if (errorArea) errorArea.style.display = 'none';
|
|
}
|
|
|
|
function showError(message) {
|
|
errorArea.style.display = 'block';
|
|
errorMessage.textContent = message;
|
|
|
|
// Scroll to error
|
|
errorArea.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
}
|
|
|
|
// Global functions
|
|
window.removeMergeFile = removeMergeFile; |