document.addEventListener('DOMContentLoaded', function() { const markdownInput = document.getElementById('markdown-input'); const htmlOutput = document.getElementById('html-output'); const selectAllBtn = document.getElementById('select-all'); const copyBtn = document.getElementById('copy'); function updateOutput() { const markdown = markdownInput.value; if (!markdown.trim()) { htmlOutput.innerHTML = ''; return; } // Convert markdown to HTML client-side const html = marked(markdown); htmlOutput.innerHTML = html; // Apply alternating column colors to tables const tables = htmlOutput.querySelectorAll('table'); tables.forEach(table => { const rows = table.querySelectorAll('tr'); rows.forEach(row => { const cells = row.querySelectorAll('td'); cells.forEach((cell, index) => { if (index % 2 === 0) { cell.style.backgroundColor = 'rgba(0, 0, 0, 0.25)'; } }); }); }); } markdownInput.addEventListener('input', updateOutput); selectAllBtn.addEventListener('click', function() { if (!htmlOutput.innerHTML.trim()) { alert('No content to select'); return; } const range = document.createRange(); range.selectNodeContents(htmlOutput); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); }); copyBtn.addEventListener('click', function() { if (!htmlOutput.innerHTML.trim()) { alert('No content to copy'); return; } // Use modern clipboard API if available if (navigator.clipboard && window.isSecureContext) { // Copy both HTML and plain text formats const htmlContent = htmlOutput.innerHTML; const textContent = htmlOutput.textContent || htmlOutput.innerText; const clipboardItem = new ClipboardItem({ 'text/html': new Blob([htmlContent], { type: 'text/html' }), 'text/plain': new Blob([textContent], { type: 'text/plain' }) }); navigator.clipboard.write([clipboardItem]).then(() => { showNotification('Rich text copied to clipboard!'); }).catch(err => { console.error('Failed to copy rich text:', err); // Fallback to plain text if rich text copying fails navigator.clipboard.writeText(textContent).then(() => { showNotification('Text copied to clipboard!'); }).catch(() => { fallbackCopy(); }); }); } else { fallbackCopy(); } }); function fallbackCopy() { const range = document.createRange(); range.selectNodeContents(htmlOutput); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); try { document.execCommand('copy'); showNotification('Rich text copied to clipboard!'); } catch (err) { console.error('Fallback copy failed:', err); showNotification('Failed to copy to clipboard', 'error'); } selection.removeAllRanges(); } function showNotification(message, type = 'success') { // Create notification element const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${type === 'error' ? '#f44336' : '#4caf50'}; color: white; padding: 12px 20px; border-radius: 4px; font-family: 'Montserrat', Arial, sans-serif; z-index: 1000; animation: slideIn 0.3s ease; `; // Add CSS animation const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } `; document.head.appendChild(style); document.body.appendChild(notification); // Remove notification after 3 seconds setTimeout(() => { notification.remove(); style.remove(); }, 3000); } // Handle authentication errors gracefully window.addEventListener('unhandledrejection', function(event) { if (event.reason && event.reason.message && event.reason.message.includes('authentication')) { showNotification('Authentication error. Please refresh and login again.', 'error'); } }); });