2025-06-16 14:22:51 +02:00

218 lines
9.6 KiB
JavaScript

// public/script.js
document.addEventListener('DOMContentLoaded', () => {
// --- Password Strength Checker for Registration ---
const passwordInput = document.getElementById('password');
const passwordStrengthDiv = document.getElementById('password-strength');
const passwordCriteriaUl = passwordStrengthDiv ? passwordStrengthDiv.querySelector('ul') : null;
if (passwordInput && passwordStrengthDiv && passwordCriteriaUl) {
const criteria = [
{ regex: /.{8,}/, message: "At least 8 characters", id: "len" },
{ regex: /[A-Z]/, message: "An uppercase letter", id: "upper" },
{ regex: /[a-z]/, message: "A lowercase letter", id: "lower" },
{ regex: /[0-9]/, message: "A number", id: "num" },
{ regex: /[^A-Za-z0-9]/, message: "A special character", id: "special" }
];
// Populate criteria list
criteria.forEach(c => {
const li = document.createElement('li');
li.id = `crit-${c.id}`;
li.textContent = `${c.message}`;
li.classList.add('invalid');
passwordCriteriaUl.appendChild(li);
});
passwordInput.addEventListener('input', () => {
const password = passwordInput.value;
let strengthScore = 0;
criteria.forEach(c => {
const li = document.getElementById(`crit-${c.id}`);
if (c.regex.test(password)) {
li.textContent = `${c.message}`;
li.classList.remove('invalid');
li.classList.add('valid');
strengthScore++;
} else {
li.textContent = `${c.message}`;
li.classList.remove('valid');
li.classList.add('invalid');
}
});
const strengthBar = document.querySelector('.password-strength-meter div');
if (strengthBar) {
strengthBar.style.width = (strengthScore / criteria.length * 100) + '%';
if (strengthScore < 2) strengthBar.style.backgroundColor = 'red';
else if (strengthScore < 4) strengthBar.style.backgroundColor = 'orange';
else strengthBar.style.backgroundColor = 'green';
}
if (password.length === 0) {
if (strengthBar) strengthBar.style.width = '0%';
}
});
// Trigger initial check if there's a value (e.g. browser autofill)
if(passwordInput.value) passwordInput.dispatchEvent(new Event('input'));
}
// --- Delete Note Confirmation and AJAX ---
document.querySelectorAll('.delete-note-btn').forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault();
if (confirm('Are you sure you want to delete this note?')) {
const noteId = this.dataset.noteId;
// Create a temporary form to submit for delete
const tempForm = document.createElement('form');
tempForm.method = 'POST';
tempForm.style.display = 'none';
const actionInput = document.createElement('input');
actionInput.type = 'hidden';
actionInput.name = 'action';
actionInput.value = 'delete_note';
tempForm.appendChild(actionInput);
const noteIdInput = document.createElement('input');
noteIdInput.type = 'hidden';
noteIdInput.name = 'note_id';
noteIdInput.value = noteId;
tempForm.appendChild(noteIdInput);
document.body.appendChild(tempForm); // Form must be in DOM to submit
// Use handleAjaxForm for consistency
const formData = new FormData(tempForm);
fetch('index.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
displayMessage(data.message, data.success ? 'success' : 'danger');
if (data.success) {
// Refresh page or remove row dynamically for better UX
// For simplicity, reload. A more advanced way is to find and remove table row.
setTimeout(() => { window.location.reload(); }, 1000);
}
})
.catch(error => {
console.error('Error:', error);
displayMessage('An error occurred during deletion.', 'danger');
})
.finally(() => {
document.body.removeChild(tempForm); // Clean up
});
}
});
});
// --- Drag and Drop File Upload ---
// ... (no changes from previous, ensure it's present)
const dropZone = document.getElementById('drop-zone');
const noteTitleInput = document.getElementById('title');
const noteContentInput = document.getElementById('content');
const markdownPreview = document.getElementById('markdown-preview');
if (dropZone && noteTitleInput && noteContentInput) {
dropZone.addEventListener('dragover', (event) => {
event.preventDefault();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', (event) => {
event.preventDefault();
dropZone.classList.remove('drag-over');
const files = event.dataTransfer.files;
if (files.length > 0) {
const file = files[0];
if (file.type === 'text/plain' || file.type === 'text/markdown' || file.name.endsWith('.md') || file.name.endsWith('.txt')) {
const reader = new FileReader();
reader.onload = (e) => {
noteTitleInput.value = file.name.replace(/\.(md|txt)$/i, '');
noteContentInput.value = e.target.result;
if (window.updateMarkdownPreview) updateMarkdownPreview();
};
reader.readAsText(file);
} else {
displayMessage('Please drop a .txt or .markdown file.', 'info');
}
}
});
}
if (noteContentInput && markdownPreview && typeof showdown !== 'undefined') {
const converter = new showdown.Converter({sanitize: true});
window.updateMarkdownPreview = function() {
markdownPreview.innerHTML = converter.makeHtml(noteContentInput.value);
}
noteContentInput.addEventListener('input', window.updateMarkdownPreview);
if(noteContentInput.value) window.updateMarkdownPreview();
} else if (noteContentInput && markdownPreview) {
noteContentInput.addEventListener('input', () => {
markdownPreview.textContent = "Preview updates on save (or include Showdown.js library for live preview).";
});
if(noteContentInput.value) markdownPreview.textContent = "Preview updates on save (or include Showdown.js library for live preview).";
}
// --- Table Sorting ---
document.querySelectorAll('.notes-table th[data-sort]').forEach(headerCell => {
headerCell.addEventListener('click', () => {
const sortBy = headerCell.dataset.sort;
const currentUrl = new URL(window.location.href);
const currentSortBy = currentUrl.searchParams.get('sort_by');
const currentSortOrder = currentUrl.searchParams.get('sort_order') || 'asc'; // Default to asc if not set
let newSortOrder = 'asc';
if (sortBy === currentSortBy && currentSortOrder.toLowerCase() === 'asc') {
newSortOrder = 'desc';
}
// If different column, or current is desc, start with asc for the new column
currentUrl.searchParams.set('sort_by', sortBy);
currentUrl.searchParams.set('sort_order', newSortOrder);
window.location.href = currentUrl.toString();
});
});
}); // End DOMContentLoaded
function displayMessage(message, type = 'info') {
const existingAlert = document.querySelector('#alert-container .alert');
if (existingAlert) {
existingAlert.remove();
}
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type}`;
alertDiv.innerHTML = message; // Use innerHTML if message contains HTML (e.g. list from server)
let alertContainer = document.getElementById('alert-container');
if (!alertContainer) {
alertContainer = document.createElement('div');
alertContainer.id = 'alert-container';
alertContainer.style.position = 'fixed';
alertContainer.style.top = '70px';
alertContainer.style.left = '50%';
alertContainer.style.transform = 'translateX(-50%)';
alertContainer.style.zIndex = '1000';
alertContainer.style.width = 'auto'; // Fit content
alertContainer.style.minWidth = '300px';
alertContainer.style.maxWidth = '90%';
document.body.prepend(alertContainer);
}
alertContainer.appendChild(alertDiv);
setTimeout(() => {
alertDiv.style.opacity = '0';
alertDiv.style.transition = 'opacity 0.5s ease-out';
setTimeout(() => {
if (alertDiv.parentNode) alertDiv.remove();
}, 500);
}, 5000);
}