/** * upaas - Frontend JavaScript utilities * Vanilla JS, no dependencies */ (function() { 'use strict'; /** * Copy text to clipboard * @param {string} text - Text to copy * @param {HTMLElement} button - Button element to update feedback */ function copyToClipboard(text, button) { const originalText = button.textContent; const originalTitle = button.getAttribute('title'); navigator.clipboard.writeText(text).then(function() { // Success feedback button.textContent = 'Copied!'; button.classList.add('text-success-500'); setTimeout(function() { button.textContent = originalText; button.classList.remove('text-success-500'); if (originalTitle) { button.setAttribute('title', originalTitle); } }, 2000); }).catch(function(err) { // Fallback for older browsers console.error('Failed to copy:', err); // Try fallback method var textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.left = '-9999px'; document.body.appendChild(textArea); textArea.select(); try { document.execCommand('copy'); button.textContent = 'Copied!'; setTimeout(function() { button.textContent = originalText; }, 2000); } catch (e) { button.textContent = 'Failed'; setTimeout(function() { button.textContent = originalText; }, 2000); } document.body.removeChild(textArea); }); } /** * Initialize copy buttons * Looks for elements with data-copy attribute */ function initCopyButtons() { var copyButtons = document.querySelectorAll('[data-copy]'); copyButtons.forEach(function(button) { button.addEventListener('click', function(e) { e.preventDefault(); var text = button.getAttribute('data-copy'); copyToClipboard(text, button); }); }); // Also handle buttons that copy content from a sibling element var copyTargetButtons = document.querySelectorAll('[data-copy-target]'); copyTargetButtons.forEach(function(button) { button.addEventListener('click', function(e) { e.preventDefault(); var targetId = button.getAttribute('data-copy-target'); var target = document.getElementById(targetId); if (target) { var text = target.textContent || target.value; copyToClipboard(text, button); } }); }); } /** * Confirm destructive actions * Looks for forms with data-confirm attribute */ function initConfirmations() { var confirmForms = document.querySelectorAll('form[data-confirm]'); confirmForms.forEach(function(form) { form.addEventListener('submit', function(e) { var message = form.getAttribute('data-confirm'); if (!confirm(message)) { e.preventDefault(); } }); }); // Also handle buttons with data-confirm var confirmButtons = document.querySelectorAll('button[data-confirm]'); confirmButtons.forEach(function(button) { button.addEventListener('click', function(e) { var message = button.getAttribute('data-confirm'); if (!confirm(message)) { e.preventDefault(); } }); }); } /** * Toggle visibility of elements * Looks for buttons with data-toggle attribute */ function initToggles() { var toggleButtons = document.querySelectorAll('[data-toggle]'); toggleButtons.forEach(function(button) { button.addEventListener('click', function(e) { e.preventDefault(); var targetId = button.getAttribute('data-toggle'); var target = document.getElementById(targetId); if (target) { target.classList.toggle('hidden'); // Update button text if data-toggle-text is provided var toggleText = button.getAttribute('data-toggle-text'); if (toggleText) { var currentText = button.textContent; button.textContent = toggleText; button.setAttribute('data-toggle-text', currentText); } } }); }); } /** * Auto-dismiss alerts after a delay * Looks for elements with data-auto-dismiss attribute */ function initAutoDismiss() { var dismissElements = document.querySelectorAll('[data-auto-dismiss]'); dismissElements.forEach(function(element) { var delay = parseInt(element.getAttribute('data-auto-dismiss'), 10) || 5000; setTimeout(function() { element.style.transition = 'opacity 0.3s ease-out'; element.style.opacity = '0'; setTimeout(function() { element.remove(); }, 300); }, delay); }); } /** * Manual dismiss for alerts * Looks for buttons with data-dismiss attribute */ function initDismissButtons() { var dismissButtons = document.querySelectorAll('[data-dismiss]'); dismissButtons.forEach(function(button) { button.addEventListener('click', function(e) { e.preventDefault(); var targetId = button.getAttribute('data-dismiss'); var target = targetId ? document.getElementById(targetId) : button.closest('.alert'); if (target) { target.style.transition = 'opacity 0.3s ease-out'; target.style.opacity = '0'; setTimeout(function() { target.remove(); }, 300); } }); }); } /** * Initialize all features when DOM is ready */ function init() { initCopyButtons(); initConfirmations(); initToggles(); initAutoDismiss(); initDismissButtons(); } // Run on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // Expose copyToClipboard globally for inline onclick handlers if needed window.upaas = { copyToClipboard: copyToClipboard }; })();