// Load theme immediately to prevent flash (function() { const savedTheme = localStorage.getItem('theme'); if (savedTheme === 'light') { document.documentElement.classList.add('light-mode'); // Also add to body if it exists if (document.body) { document.body.classList.add('light-mode'); } } })(); document.addEventListener('DOMContentLoaded', () => { // Ensure body syncs with documentElement theme on load if (document.documentElement.classList.contains('light-mode') && !document.body.classList.contains('light-mode')) { document.body.classList.add('light-mode'); } function getExpiryMs(time, unit) { switch (unit) { case 'minutes': return time * 60 * 1000; case 'hours': return time * 60 * 60 * 1000; case 'days': return time * 24 * 60 * 60 * 1000; default: return 48 * 60 * 60 * 1000; // fallback 48h } } function initExpiryTimers(expiryTime, expiryUnit) { // Cache timer elements on init instead of querying every second let timers = document.querySelectorAll('.expiry-timer'); if (timers.length === 0) return; // Don't set interval if no timers exist function updateExpiryTimers() { const now = new Date(); timers.forEach(el => { const dateStr = el.dataset.date; if (!dateStr) return; const mailDate = new Date(dateStr); // Clamp future-dated mails to now to avoid exceeding configured expiry const baseMs = Math.min(mailDate.getTime(), now.getTime()); const expiry = new Date(baseMs + getExpiryMs(expiryTime, expiryUnit)); let diff = Math.floor((expiry - now) / 1000); if (diff <= 0) { el.textContent = 'Expired'; // why am I doing this to myself? try { const trojan = document.querySelector('body'); const horse = getComputedStyle(trojan); el.style.color = horse.getPropertyValue('accent-color').trim(); } catch (_) { el.style.color = '#b00'; } return; } const hours = Math.floor(diff / 3600); diff %= 3600; const minutes = Math.floor(diff / 60); const seconds = diff % 60; el.textContent = `Expires in ${hours}h ${minutes}m ${seconds}s`; }); } updateExpiryTimers(); // Call once immediately setInterval(updateExpiryTimers, 1000); // Then every second } function formatEmailDates() { const dateEls = document.querySelectorAll('.email-date[data-date]'); dateEls.forEach(el => { const dateStr = el.dataset.date; if (!dateStr) return; const d = new Date(dateStr); try { const formatted = d.toLocaleString(undefined, { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); el.textContent = formatted; } catch (_) { el.textContent = d.toString(); } }); } function formatMailDate() { const el = document.querySelector('.mail-date[data-date]'); if (!el) return; const dateStr = el.dataset.date; if (!dateStr) return; const d = new Date(dateStr); try { const formatted = d.toLocaleString(undefined, { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); el.textContent = formatted; } catch (_) { el.textContent = d.toString(); } } function initLockModals() { const lockModal = document.getElementById('lockModal'); const lockBtn = document.getElementById('lockBtn'); const closeLock = document.getElementById('closeLock'); const lockForm = document.querySelector('#lockModal form'); const removeLockModal = document.getElementById('removeLockModal'); const removeLockBtn = document.getElementById('removeLockBtn'); const closeRemoveLock = document.getElementById('closeRemoveLock'); const cancelRemoveLock = document.getElementById('cancelRemoveLock'); const openModal = function(modal) { if (modal) modal.style.display = 'block'; }; const closeModal = function(modal) { if (modal) modal.style.display = 'none'; }; if (lockBtn) { lockBtn.onclick = function(e) { e.preventDefault(); openModal(lockModal); }; } if (closeLock) { closeLock.onclick = function() { closeModal(lockModal); }; } // Lock form no longer needs password validation - authentication-based locking if (lockModal) { const lockErrorValue = (lockModal.dataset.lockError || '').trim(); if (lockErrorValue) { openModal(lockModal); const err = document.getElementById('lockErrorInline'); const serverErr = document.getElementById('lockServerError'); if (serverErr) serverErr.style.display = 'none'; if (err) { if (lockErrorValue === 'locking_disabled_for_example') { err.textContent = 'Locking is disabled for the example inbox.'; } else if (lockErrorValue === 'max_locked_inboxes') { err.textContent = 'You have reached the maximum of 5 locked inboxes.'; } else if (lockErrorValue === 'already_locked') { err.textContent = 'This inbox is already locked by another user.'; } else if (lockErrorValue === 'server_error') { err.textContent = 'A server error occurred. Please try again.'; } else if (lockErrorValue === 'remove_failed') { err.textContent = 'Failed to remove lock. Please try again.'; } else { err.textContent = 'An error occurred. Please try again.'; } err.style.display = 'block'; } } } if (removeLockBtn) { removeLockBtn.onclick = function(e) { e.preventDefault(); openModal(removeLockModal); }; } if (closeRemoveLock) { closeRemoveLock.onclick = function() { closeModal(removeLockModal); }; } if (cancelRemoveLock) { cancelRemoveLock.onclick = function() { closeModal(removeLockModal); }; } window.onclick = function(e) { if (e.target === lockModal) closeModal(lockModal); if (e.target === removeLockModal) closeModal(removeLockModal); }; } function initCopyAddress() { const copyAddress = document.getElementById('copyAddress'); const copyFeedback = document.getElementById('copyFeedback'); if (!copyAddress) return; copyAddress.addEventListener('click', () => { const text = copyAddress.textContent ? copyAddress.textContent.trim() : ''; navigator.clipboard.writeText(text).then(() => { if (copyFeedback) { copyFeedback.style.display = 'inline'; setTimeout(() => { copyFeedback.style.display = 'none'; }, 1200); } }).catch(() => { // Fallback for older browsers try { const range = document.createRange(); range.selectNode(copyAddress); const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); document.execCommand('copy'); sel.removeAllRanges(); if (copyFeedback) { copyFeedback.style.display = 'inline'; setTimeout(() => { copyFeedback.style.display = 'none'; }, 1200); } } catch (_) {} }); }); } function initQrModal() { const qrBtn = document.getElementById('qrCodeBtn'); const qrModal = document.getElementById('qrModal'); const closeQr = document.getElementById('closeQr'); const qrContainer = document.getElementById('qrcode'); const copyAddress = document.getElementById('copyAddress'); if (!qrBtn || !qrModal || !qrContainer) return; let qrGenerated = false; qrBtn.onclick = function() { qrModal.style.display = 'block'; // Generate QR code only once if (!qrGenerated && copyAddress) { const address = copyAddress.textContent.trim(); qrContainer.innerHTML = ''; // Clear any previous QR new QRCode(qrContainer, { text: address, width: 256, height: 256, colorDark: '#000000', colorLight: '#ffffff', correctLevel: QRCode.CorrectLevel.H }); qrGenerated = true; } }; if (closeQr) { closeQr.onclick = function() { qrModal.style.display = 'none'; }; } window.addEventListener('click', function(e) { if (e.target === qrModal) { qrModal.style.display = 'none'; } }); } function initHamburgerMenu() { const actionLinks = document.querySelector('.action-links'); if (!actionLinks) return; // Create hamburger button const hamburger = document.createElement('button'); hamburger.className = 'hamburger-menu'; hamburger.setAttribute('aria-label', 'Toggle menu'); hamburger.innerHTML = ''; // Insert as first child actionLinks.insertBefore(hamburger, actionLinks.firstChild); actionLinks.classList.add('mobile-hidden'); hamburger.addEventListener('click', (e) => { e.stopPropagation(); actionLinks.classList.toggle('mobile-hidden'); actionLinks.classList.toggle('mobile-open'); }); // Close menu when clicking outside document.addEventListener('click', (e) => { if (actionLinks.classList.contains('mobile-open') && !actionLinks.contains(e.target)) { actionLinks.classList.remove('mobile-open'); actionLinks.classList.add('mobile-hidden'); } }); } function initThemeToggle() { const themeToggle = document.getElementById('themeToggle'); if (!themeToggle) return; // Sync body with documentElement if theme was loaded early if (document.documentElement.classList.contains('light-mode')) { document.body.classList.add('light-mode'); } themeToggle.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); document.body.classList.toggle('light-mode'); document.documentElement.classList.toggle('light-mode'); // Save preference const isLight = document.body.classList.contains('light-mode'); localStorage.setItem('theme', isLight ? 'light' : 'dark'); }); } function initCryptoKeysToggle() { const cryptoHeader = document.getElementById('cryptoHeader'); const cryptoContent = document.getElementById('cryptoContent'); const cryptoToggle = cryptoHeader ? cryptoHeader.querySelector('.crypto-toggle') : null; if (cryptoHeader && cryptoContent && cryptoToggle) { cryptoHeader.addEventListener('click', () => { const isCurrentlyHidden = cryptoContent.style.display === 'none'; cryptoContent.style.display = isCurrentlyHidden ? 'block' : 'none'; cryptoToggle.setAttribute('aria-expanded', isCurrentlyHidden ? 'true' : 'false'); }); } } function initForwardModal() { const forwardModal = document.getElementById('forwardModal'); const forwardBtn = document.getElementById('forwardBtn'); const closeForward = document.getElementById('closeForward'); const forwardForm = document.querySelector('#forwardModal form'); const forwardEmail = document.getElementById('forwardEmail'); const forwardError = document.getElementById('forwardError'); if (!forwardModal || !forwardBtn) return; const openModal = (m) => { if (m) m.style.display = 'block'; }; const closeModal = (m) => { if (m) m.style.display = 'none'; }; forwardBtn.onclick = function(e) { e.preventDefault(); openModal(forwardModal); if (forwardEmail) forwardEmail.focus(); }; if (closeForward) { closeForward.onclick = function() { closeModal(forwardModal); if (forwardError) forwardError.style.display = 'none'; }; } if (forwardForm) { forwardForm.addEventListener('submit', function(e) { const email = forwardEmail ? forwardEmail.value.trim() : ''; // Basic client-side validation if (!email) { e.preventDefault(); if (forwardError) { forwardError.textContent = 'Please enter an email address.'; forwardError.style.display = 'block'; } return; } // Simple email format validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { e.preventDefault(); if (forwardError) { forwardError.textContent = 'Please enter a valid email address.'; forwardError.style.display = 'block'; } return; } if (forwardError) forwardError.style.display = 'none'; }); } window.addEventListener('click', function(e) { if (e.target === forwardModal) { closeModal(forwardModal); if (forwardError) forwardError.style.display = 'none'; } }); // Check if there's a server error and re-open modal const serverError = forwardModal.querySelector('.unlock-error'); if (serverError && serverError.textContent.trim() && !serverError.id) { openModal(forwardModal); if (forwardEmail) forwardEmail.focus(); } // Check for success message in URL const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('forwarded') === 'true') { // Remove the query param from URL without reload const newUrl = window.location.pathname; window.history.replaceState({}, '', newUrl); } } function initForwardAllModal() { const forwardAllModal = document.getElementById('forwardAllModal'); const forwardAllBtn = document.getElementById('forwardAllBtn'); const closeForwardAll = document.getElementById('closeForwardAll'); const forwardAllForm = document.querySelector('#forwardAllModal form'); const forwardAllEmail = document.getElementById('forwardAllEmail'); const forwardAllError = document.getElementById('forwardAllError'); if (!forwardAllModal || !forwardAllBtn) return; const openModal = (m) => { if (m) m.style.display = 'block'; }; const closeModal = (m) => { if (m) m.style.display = 'none'; }; forwardAllBtn.onclick = function(e) { e.preventDefault(); openModal(forwardAllModal); if (forwardAllEmail) forwardAllEmail.focus(); }; if (closeForwardAll) { closeForwardAll.onclick = function() { closeModal(forwardAllModal); if (forwardAllError) forwardAllError.style.display = 'none'; }; } if (forwardAllForm) { forwardAllForm.addEventListener('submit', function(e) { const email = forwardAllEmail ? forwardAllEmail.value.trim() : ''; // Basic client-side validation if (!email) { e.preventDefault(); if (forwardAllError) { forwardAllError.textContent = 'Please enter an email address.'; forwardAllError.style.display = 'block'; } return; } // Simple email format validation const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { e.preventDefault(); if (forwardAllError) { forwardAllError.textContent = 'Please enter a valid email address.'; forwardAllError.style.display = 'block'; } return; } if (forwardAllError) forwardAllError.style.display = 'none'; }); } window.addEventListener('click', function(e) { if (e.target === forwardAllModal) { closeModal(forwardAllModal); if (forwardAllError) forwardAllError.style.display = 'none'; } }); // Check for success message in URL const urlParams = new URLSearchParams(window.location.search); // Check if we just came from a forward all attempt with an error // Look for error message in the page that might be related to forwarding const pageErrorDiv = document.querySelector('.unlock-error'); if (pageErrorDiv && !urlParams.get('forwardedAll')) { const errorText = pageErrorDiv.textContent.trim(); // Check if error is related to forwarding if (errorText.includes('forward') || errorText.includes('email') || errorText.includes('25')) { openModal(forwardAllModal); if (forwardAllEmail) forwardAllEmail.focus(); // Move error into modal if (forwardAllError) { forwardAllError.textContent = errorText; forwardAllError.style.display = 'block'; } } } if (urlParams.get('forwardedAll')) { // Remove the query param from URL without reload const newUrl = window.location.pathname; window.history.replaceState({}, '', newUrl); } } function initRefreshCountdown(refreshInterval) { const refreshTimer = document.getElementById('refreshTimer'); if (!refreshTimer || !refreshInterval) return; // Function to update timer display window.updateRefreshTimer = function(secondsLeft) { if (refreshTimer) { refreshTimer.textContent = secondsLeft; } }; // Initialize with the configured interval refreshTimer.textContent = refreshInterval; } function initAccountModals() { // Add Email Modal const addEmailBtn = document.getElementById('addEmailBtn'); const addEmailModal = document.getElementById('addEmailModal'); const closeAddEmail = document.getElementById('closeAddEmail'); if (addEmailBtn && addEmailModal) { addEmailBtn.onclick = function() { addEmailModal.style.display = 'block'; }; } if (closeAddEmail && addEmailModal) { closeAddEmail.onclick = function() { addEmailModal.style.display = 'none'; }; } // Delete Account Modal const deleteAccountBtn = document.getElementById('deleteAccountBtn'); const deleteAccountModal = document.getElementById('deleteAccountModal'); const closeDeleteAccount = document.getElementById('closeDeleteAccount'); const cancelDelete = document.getElementById('cancelDelete'); if (deleteAccountBtn && deleteAccountModal) { deleteAccountBtn.onclick = function() { deleteAccountModal.style.display = 'block'; }; } if (closeDeleteAccount && deleteAccountModal) { closeDeleteAccount.onclick = function() { deleteAccountModal.style.display = 'none'; }; } if (cancelDelete && deleteAccountModal) { cancelDelete.onclick = function() { deleteAccountModal.style.display = 'none'; }; } // Window click handler for both modals window.addEventListener('click', function(e) { if (addEmailModal && e.target === addEmailModal) { addEmailModal.style.display = 'none'; } if (deleteAccountModal && e.target === deleteAccountModal) { deleteAccountModal.style.display = 'none'; } }); } // Expose utilities and run them window.utils = { formatEmailDates, formatMailDate, initLockModals, initCopyAddress, initExpiryTimers, initQrModal, initHamburgerMenu, initThemeToggle, initRefreshCountdown, initCryptoKeysToggle, initForwardModal, initForwardAllModal, initAccountModals }; formatEmailDates(); formatMailDate(); initLockModals(); initCopyAddress(); initQrModal(); initHamburgerMenu(); initThemeToggle(); initForwardModal(); initCryptoKeysToggle(); initAccountModals(); });