new file: QUICKSTART.md
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
This commit is contained in:
342
static/js/pdf-tools.js
Normal file
342
static/js/pdf-tools.js
Normal file
@@ -0,0 +1,342 @@
|
||||
// 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;
|
||||
Reference in New Issue
Block a user