modified: QUICKSTART.md
modified: app.py deleted: output/.gitkeep modified: static/css/style.css modified: static/js/pdf-tools.js modified: templates/pdf_tools.html deleted: uploads/.gitkeep
This commit is contained in:
@@ -160,22 +160,56 @@ function displayMergeFiles() {
|
||||
|
||||
function createMergeFileItem(file, index) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'list-group-item';
|
||||
div.className = 'list-group-item pdf-item-enhanced';
|
||||
div.dataset.index = index;
|
||||
|
||||
// Initialize rotation if not set
|
||||
if (file.rotation === undefined) {
|
||||
file.rotation = 0;
|
||||
}
|
||||
|
||||
// Create preview element
|
||||
const previewElement = file.preview ?
|
||||
`<img src="/uploads/${file.preview}" class="pdf-preview size-medium rotate-${file.rotation}"
|
||||
alt="${file.original_name}" onclick="showPdfModal('${file.preview}', '${file.original_name}', ${index})">` :
|
||||
`<div class="pdf-preview pdf-no-preview size-medium rotate-${file.rotation}">
|
||||
<i class="fas fa-file-pdf"></i>
|
||||
</div>`;
|
||||
|
||||
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 class="pdf-preview-container me-3">
|
||||
${previewElement}
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="pdf-info">
|
||||
<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 class="rotation-controls">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger rotation-btn"
|
||||
onclick="rotatePdf(${index}, -90)" title="Links drehen">
|
||||
<i class="fas fa-undo"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger rotation-btn"
|
||||
onclick="rotatePdf(${index}, 90)" title="Rechts drehen">
|
||||
<i class="fas fa-redo"></i>
|
||||
</button>
|
||||
<small class="text-muted ms-2">${file.rotation}°</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-actions">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeMergeFile(${index})">
|
||||
<div class="pdf-controls">
|
||||
<div class="d-flex gap-1 mb-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="movePdfUp(${index})"
|
||||
${index === 0 ? 'disabled' : ''} title="Nach oben">
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="movePdfDown(${index})"
|
||||
${index === pdfToolsFiles.length - 1 ? 'disabled' : ''} title="Nach unten">
|
||||
<i class="fas fa-arrow-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeMergeFile(${index})" title="Entfernen">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -210,6 +244,108 @@ function removeMergeFile(index) {
|
||||
showNotification('PDF-Datei entfernt.', 'info');
|
||||
}
|
||||
|
||||
function rotatePdf(index, degrees) {
|
||||
if (index >= 0 && index < pdfToolsFiles.length) {
|
||||
pdfToolsFiles[index].rotation = (pdfToolsFiles[index].rotation + degrees) % 360;
|
||||
if (pdfToolsFiles[index].rotation < 0) {
|
||||
pdfToolsFiles[index].rotation += 360;
|
||||
}
|
||||
displayMergeFiles();
|
||||
showNotification(`PDF um ${degrees}° gedreht.`, 'info');
|
||||
}
|
||||
}
|
||||
|
||||
function movePdfUp(index) {
|
||||
if (index > 0) {
|
||||
[pdfToolsFiles[index], pdfToolsFiles[index - 1]] = [pdfToolsFiles[index - 1], pdfToolsFiles[index]];
|
||||
displayMergeFiles();
|
||||
}
|
||||
}
|
||||
|
||||
function movePdfDown(index) {
|
||||
if (index < pdfToolsFiles.length - 1) {
|
||||
[pdfToolsFiles[index], pdfToolsFiles[index + 1]] = [pdfToolsFiles[index + 1], pdfToolsFiles[index]];
|
||||
displayMergeFiles();
|
||||
}
|
||||
}
|
||||
|
||||
function showPdfModal(previewFilename, originalName, index) {
|
||||
// Create modal if it doesn't exist
|
||||
let modal = document.getElementById('pdf-modal');
|
||||
if (!modal) {
|
||||
modal = document.createElement('div');
|
||||
modal.className = 'modal fade image-modal';
|
||||
modal.id = 'pdf-modal';
|
||||
modal.setAttribute('tabindex', '-1');
|
||||
modal.setAttribute('aria-hidden', 'true');
|
||||
|
||||
modal.innerHTML = `
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="pdf-modal-title">${originalName}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<img id="modal-pdf-preview" src="/uploads/${previewFilename}"
|
||||
class="img-fluid rotate-${pdfToolsFiles[index].rotation}" alt="${originalName}">
|
||||
<p class="text-muted mt-2 mb-0">Vorschau der ersten Seite</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group me-auto">
|
||||
<button type="button" class="btn btn-outline-danger" onclick="rotatePdfInModal(${index}, -90)">
|
||||
<i class="fas fa-undo me-1"></i>Links drehen
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger" onclick="rotatePdfInModal(${index}, 90)">
|
||||
<i class="fas fa-redo me-1"></i>Rechts drehen
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
} else {
|
||||
// Update existing modal
|
||||
document.getElementById('pdf-modal-title').textContent = originalName;
|
||||
const modalPreview = document.getElementById('modal-pdf-preview');
|
||||
modalPreview.src = `/uploads/${previewFilename}`;
|
||||
modalPreview.alt = originalName;
|
||||
modalPreview.className = `img-fluid rotate-${pdfToolsFiles[index].rotation}`;
|
||||
|
||||
// Update rotation buttons
|
||||
const rotateButtons = modal.querySelectorAll('.btn-outline-danger');
|
||||
rotateButtons[0].onclick = () => rotatePdfInModal(index, -90);
|
||||
rotateButtons[1].onclick = () => rotatePdfInModal(index, 90);
|
||||
}
|
||||
|
||||
// Show modal
|
||||
const bootstrapModal = new bootstrap.Modal(modal);
|
||||
bootstrapModal.show();
|
||||
}
|
||||
|
||||
function rotatePdfInModal(index, degrees) {
|
||||
rotatePdf(index, degrees);
|
||||
|
||||
// Update modal preview
|
||||
const modalPreview = document.getElementById('modal-pdf-preview');
|
||||
modalPreview.className = `img-fluid rotate-${pdfToolsFiles[index].rotation}`;
|
||||
}
|
||||
|
||||
function updatePdfPreviewSize() {
|
||||
const previewSize = document.getElementById('pdf-preview-size')?.value || 'medium';
|
||||
const previews = document.querySelectorAll('.pdf-preview');
|
||||
|
||||
previews.forEach(preview => {
|
||||
// Remove existing size classes
|
||||
preview.classList.remove('size-small', 'size-medium', 'size-large');
|
||||
// Add new size class
|
||||
preview.classList.add('size-' + previewSize);
|
||||
});
|
||||
}
|
||||
|
||||
async function mergePdfs() {
|
||||
if (pdfToolsFiles.length < 2) {
|
||||
showError('Mindestens 2 PDF-Dateien erforderlich.');
|
||||
@@ -220,11 +356,16 @@ async function mergePdfs() {
|
||||
processingModal.show();
|
||||
|
||||
try {
|
||||
const filenames = pdfToolsFiles.map(file => file.filename);
|
||||
// Include rotation data for each file
|
||||
const filesWithRotation = pdfToolsFiles.map(file => ({
|
||||
filename: file.filename,
|
||||
rotation: file.rotation || 0,
|
||||
original_name: file.original_name
|
||||
}));
|
||||
|
||||
const response = await makeRequest('/api/merge-pdfs', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ filenames })
|
||||
body: JSON.stringify({ files: filesWithRotation })
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
@@ -283,9 +424,30 @@ function displaySplitFile() {
|
||||
document.getElementById('split-file-details').textContent =
|
||||
`${currentPdfFile.page_count} Seiten • ${formatFileSize(currentPdfFile.size)}`;
|
||||
|
||||
// PDF-Vorschau anzeigen falls verfügbar
|
||||
const previewContainer = document.getElementById('split-preview-container');
|
||||
if (currentPdfFile.preview) {
|
||||
previewContainer.innerHTML = `
|
||||
<img src="/uploads/${currentPdfFile.preview}" class="pdf-preview size-medium"
|
||||
alt="${currentPdfFile.original_name}" onclick="showSplitPdfModal()">
|
||||
`;
|
||||
} else {
|
||||
previewContainer.innerHTML = `
|
||||
<div class="pdf-preview pdf-no-preview size-medium">
|
||||
<i class="fas fa-file-pdf"></i>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
splitFileInfo.style.display = 'block';
|
||||
}
|
||||
|
||||
function showSplitPdfModal() {
|
||||
if (currentPdfFile && currentPdfFile.preview) {
|
||||
showPdfModal(currentPdfFile.preview, currentPdfFile.original_name, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async function convertPdfToImages() {
|
||||
if (!currentPdfFile) {
|
||||
showError('Keine PDF-Datei ausgewählt.');
|
||||
@@ -339,4 +501,11 @@ function showError(message) {
|
||||
}
|
||||
|
||||
// Global functions
|
||||
window.removeMergeFile = removeMergeFile;
|
||||
window.removeMergeFile = removeMergeFile;
|
||||
window.rotatePdf = rotatePdf;
|
||||
window.movePdfUp = movePdfUp;
|
||||
window.movePdfDown = movePdfDown;
|
||||
window.showPdfModal = showPdfModal;
|
||||
window.rotatePdfInModal = rotatePdfInModal;
|
||||
window.updatePdfPreviewSize = updatePdfPreviewSize;
|
||||
window.showSplitPdfModal = showSplitPdfModal;
|
||||
Reference in New Issue
Block a user