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:
190
static/js/main.js
Normal file
190
static/js/main.js
Normal file
@@ -0,0 +1,190 @@
|
||||
// PDF Editor - Main JavaScript Functions
|
||||
|
||||
// Global variables
|
||||
let uploadedFiles = [];
|
||||
let sortableInstance = null;
|
||||
|
||||
// Utility functions
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function getFileIcon(filename) {
|
||||
const extension = filename.toLowerCase().split('.').pop();
|
||||
const iconMap = {
|
||||
'pdf': 'fas fa-file-pdf text-danger',
|
||||
'jpg': 'fas fa-file-image text-success',
|
||||
'jpeg': 'fas fa-file-image text-success',
|
||||
'png': 'fas fa-file-image text-success',
|
||||
'gif': 'fas fa-file-image text-success',
|
||||
'bmp': 'fas fa-file-image text-success',
|
||||
'tiff': 'fas fa-file-image text-success',
|
||||
'zip': 'fas fa-file-archive text-warning'
|
||||
};
|
||||
return iconMap[extension] || 'fas fa-file text-muted';
|
||||
}
|
||||
|
||||
// Show notification
|
||||
function showNotification(message, type = 'info') {
|
||||
// Create notification element
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`;
|
||||
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; max-width: 400px;';
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Auto remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Show/hide loading state
|
||||
function setLoadingState(element, loading = true) {
|
||||
if (loading) {
|
||||
element.disabled = true;
|
||||
const originalText = element.innerHTML;
|
||||
element.dataset.originalText = originalText;
|
||||
element.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Verarbeitung...';
|
||||
} else {
|
||||
element.disabled = false;
|
||||
element.innerHTML = element.dataset.originalText || element.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
// AJAX helper function
|
||||
async function makeRequest(url, options = {}) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
},
|
||||
...options
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// File upload with progress
|
||||
async function uploadFiles(files, endpoint, progressCallback) {
|
||||
const formData = new FormData();
|
||||
|
||||
if (Array.isArray(files)) {
|
||||
files.forEach(file => formData.append('files', file));
|
||||
} else {
|
||||
formData.append('file', files);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
// Upload progress
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.lengthComputable && progressCallback) {
|
||||
const percentComplete = (e.loaded / e.total) * 100;
|
||||
progressCallback(percentComplete);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
resolve(response);
|
||||
} catch (error) {
|
||||
reject(new Error('Invalid JSON response'));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Upload failed with status: ${xhr.status}`));
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
reject(new Error('Upload failed'));
|
||||
});
|
||||
|
||||
xhr.open('POST', endpoint);
|
||||
xhr.send(formData);
|
||||
});
|
||||
}
|
||||
|
||||
// Drag and drop functionality
|
||||
function setupDragAndDrop(element, callback) {
|
||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
element.addEventListener(eventName, preventDefaults, false);
|
||||
});
|
||||
|
||||
function preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
['dragenter', 'dragover'].forEach(eventName => {
|
||||
element.addEventListener(eventName, () => {
|
||||
element.classList.add('dragover');
|
||||
}, false);
|
||||
});
|
||||
|
||||
['dragleave', 'drop'].forEach(eventName => {
|
||||
element.addEventListener(eventName, () => {
|
||||
element.classList.remove('dragover');
|
||||
}, false);
|
||||
});
|
||||
|
||||
element.addEventListener('drop', (e) => {
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
callback(files);
|
||||
}, false);
|
||||
}
|
||||
|
||||
// Sortable list functionality
|
||||
function setupSortable(container, onUpdate) {
|
||||
if (typeof Sortable !== 'undefined') {
|
||||
return Sortable.create(container, {
|
||||
animation: 150,
|
||||
ghostClass: 'sortable-ghost',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-drag',
|
||||
onUpdate: onUpdate
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Initialize tooltips
|
||||
function initializeTooltips() {
|
||||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeTooltips();
|
||||
|
||||
// Add fade-in animation to main content
|
||||
const mainContent = document.querySelector('main');
|
||||
if (mainContent) {
|
||||
mainContent.classList.add('fade-in');
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user