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')); } // --- Drag and Drop File Upload --- 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); }