This commit is contained in:
pika 2025-04-17 12:05:22 +02:00
parent 17885b005c
commit f5c8e9ee23
4 changed files with 756 additions and 44 deletions

View file

@ -397,23 +397,71 @@
const docActions = document.createElement('div');
docActions.className = 'actions absolute right-0 hidden group-hover:flex items-center bg-gray-800 px-1';
// Edit doc button
const editDocButton = document.createElement('button');
editDocButton.className = 'p-1 text-gray-500 hover:text-primary rounded transition-colors';
editDocButton.title = 'Edit Document';
editDocButton.innerHTML = '<i class="mdi mdi-pencil-outline text-sm"></i>';
editDocButton.addEventListener('click', function(e) {
// Edit document button
const editBtn = document.createElement('button');
editBtn.className = 'p-1 text-gray-500 hover:text-primary rounded transition-colors';
editBtn.title = 'Edit document';
editBtn.innerHTML = '<i class="mdi mdi-pencil-outline text-sm"></i>';
editBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
window.location.href = `/document/${doc.id}/edit`;
});
docActions.appendChild(editDocButton);
docActions.appendChild(editBtn);
// Delete document button
const deleteBtn = document.createElement('button');
deleteBtn.className = 'p-1 text-gray-500 hover:text-red-500 rounded transition-colors';
deleteBtn.title = 'Delete document';
deleteBtn.innerHTML = '<i class="mdi mdi-delete-outline text-sm"></i>';
deleteBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
// Show confirmation dialog
if (confirm(`Are you sure you want to delete "${doc.title}"? This cannot be undone.`)) {
// Send delete request
fetch(`/api/document/${doc.id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
}
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to delete');
}
return response.json();
})
.then(data => {
// Remove the document from the DOM
docLi.remove();
// Show notification
showNotification('Document deleted successfully');
// If we're on the document's page, redirect to the category or home
const currentPath = window.location.pathname;
if (currentPath === `/document/${doc.id}` || currentPath === `/document/${doc.id}/edit`) {
window.location.href = `/category/${category.id}`;
}
})
.catch(error => {
console.error('Error:', error);
showNotification('Error deleting document', 'error');
});
}
});
docActions.appendChild(deleteBtn);
docLi.appendChild(docLink);
docLi.appendChild(docActions);
documentsUl.appendChild(docLi);
})
.catch(error => console.error('Error fetching document:', error));
.catch(error => {
console.error(`Error fetching document ${docId}:`, error);
});
});
}
@ -477,10 +525,12 @@
}
// Helper function to show notifications
function showNotification(message) {
function showNotification(message, type = 'success') {
const notification = document.createElement('div');
notification.className = 'fixed bottom-4 right-4 bg-primary/90 text-white px-4 py-2 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 flex items-center';
notification.innerHTML = `<i class="mdi mdi-check-circle mr-2"></i><span>${message}</span>`;
const bgColor = type === 'success' ? 'bg-green-600' : 'bg-red-600';
notification.className = `fixed bottom-4 right-4 ${bgColor} text-white px-4 py-2 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 z-50`;
notification.textContent = message;
document.body.appendChild(notification);
@ -490,7 +540,7 @@
}, 3000);
}
// Helper function to get CSRF token from meta tag
// Helper function to get CSRF token
function getCsrfToken() {
return document.querySelector('meta[name="csrf-token"]').getAttribute('content');
}
@ -589,5 +639,125 @@
<script src="{{ url_for('static', filename='js/utils.js') }}"></script>
{% block extra_js %}{% endblock %}
<!-- Add this modal to the bottom of the body, before the closing body tag -->
<div id="delete-category-modal" class="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full p-6">
<h3 class="text-lg font-medium text-slate-900 mb-4">Delete Category</h3>
<p class="text-slate-700 mb-2">Are you sure you want to delete "<span id="category-delete-name" class="font-medium"></span>"?</p>
<div class="mt-4 space-y-3">
<div class="flex items-center">
<input type="radio" id="preserve-documents" name="delete-option" value="preserve" class="mr-2" checked>
<label for="preserve-documents" class="text-sm text-slate-700">
Move documents and subcategories to parent category
</label>
</div>
<div class="flex items-center">
<input type="radio" id="delete-all" name="delete-option" value="delete" class="mr-2">
<label for="delete-all" class="text-sm text-slate-700">
Delete all documents and subcategories
</label>
</div>
</div>
<div class="mt-6 flex justify-end space-x-3">
<button id="cancel-delete-category" class="px-4 py-2 bg-slate-100 text-slate-700 rounded-md hover:bg-slate-200">
Cancel
</button>
<button id="confirm-delete-category" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700">
Delete
</button>
</div>
</div>
</div>
<!-- Add this JavaScript at the bottom of the file, before the closing body tag -->
<script>
// Category deletion functionality
const categoryDeleteModal = document.getElementById('delete-category-modal');
const categoryNameSpan = document.getElementById('category-delete-name');
const cancelDeleteCategoryBtn = document.getElementById('cancel-delete-category');
const confirmDeleteCategoryBtn = document.getElementById('confirm-delete-category');
let currentCategoryId = null;
// Show notification function
function showNotification(message, type = 'success') {
const notification = document.createElement('div');
notification.className = `fixed bottom-4 right-4 p-4 rounded-md shadow-lg z-50 ${
type === 'success' ? 'bg-green-500' : 'bg-red-500'
} text-white`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
// Show delete confirmation modal
document.querySelectorAll('.delete-category-btn').forEach(btn => {
btn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
// Close any open dropdown
document.querySelectorAll('.dropdown-menu:not(.hidden)').forEach(menu => {
menu.classList.add('hidden');
});
const categoryId = this.getAttribute('data-category-id');
const categoryName = this.getAttribute('data-category-name');
categoryNameSpan.textContent = categoryName;
currentCategoryId = categoryId;
categoryDeleteModal.classList.remove('hidden');
});
});
// Cancel category deletion
cancelDeleteCategoryBtn.addEventListener('click', function() {
categoryDeleteModal.classList.add('hidden');
currentCategoryId = null;
});
// Confirm category deletion
confirmDeleteCategoryBtn.addEventListener('click', function() {
if (currentCategoryId) {
const preserveContents = document.getElementById('preserve-documents').checked;
// Send delete request to server
fetch(`/api/category/${currentCategoryId}?preserve_contents=${preserveContents}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
}
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to delete category');
}
return response.json();
})
.then(data => {
// Close the modal
categoryDeleteModal.classList.add('hidden');
// Show a success message
showNotification('Category deleted successfully');
// Reload the page to refresh the category tree
setTimeout(() => {
window.location.reload();
}, 1000);
})
.catch(error => {
console.error('Error:', error);
showNotification('Error deleting category', 'error');
});
}
});
</script>
</body>
</html>