'use strict'; var iframeObservers = new WeakMap(); document.addEventListener( 'DOMContentLoaded', function () { initializeEmailList(); } ); function initializeEmailList() { var emailItems = document.querySelectorAll('.email-item'); emailItems.forEach(function (item) { var summary = item.querySelector('.email-summary'); var downloadButton = item.querySelector('.download-icon'); if (summary) { summary.addEventListener( 'click', function (event) { if ( event.target.closest( '.download-icon' ) ) { return; } toggleEmail(item); } ); summary.addEventListener( 'keydown', function (event) { if ( event.key !== 'Enter' && event.key !== ' ' ) { return; } if ( event.target.closest( '.download-icon' ) ) { return; } event.preventDefault(); toggleEmail(item); } ); } if (downloadButton) { downloadButton.addEventListener( 'click', function (event) { event.stopPropagation(); var id = item.dataset.id; if (!id) { console.error( 'Email ID is missing' ); return; } downloadEmail( event, id ); } ); } }); } function toggleEmail(item) { var id = item.dataset.id; if (!id) { console.error( 'Email ID is missing' ); return; } var summary = item.querySelector('.email-summary'); var detail = item.querySelector('.email-detail'); var toggleIcon = item.querySelector('.toggle'); var iframe = item.querySelector( '.email-content-frame' ); if (!detail || !iframe) { console.error( 'Email UI elements are missing for:', id ); return; } var isHidden = detail.classList.contains('hidden'); if (isHidden) { detail.classList.remove('hidden'); if (toggleIcon) { toggleIcon.classList.add( 'rotated' ); } if (summary) { summary.setAttribute( 'aria-expanded', 'true' ); } loadEmailContent( id, iframe ); } else { detail.classList.add('hidden'); if (toggleIcon) { toggleIcon.classList.remove( 'rotated' ); } if (summary) { summary.setAttribute( 'aria-expanded', 'false' ); } } } function loadEmailContent(id, iframe) { if ( iframe.dataset.loaded === 'true' ) { resizeIframe(iframe); return; } if ( iframe.dataset.loading === 'true' ) { return; } iframe.dataset.loading = 'true'; fetch( '/api/view?id=' + encodeURIComponent(id), { method: 'GET', credentials: 'same-origin' } ) .then(function (response) { handleUnauthorized(response); if (!response.ok) { throw new Error( 'HTTP error ' + response.status ); } return response.text(); }) .then(function (data) { resetIframeObserver(iframe); writeEmailToIframe( iframe, data ); iframe.dataset.loaded = 'true'; delete iframe.dataset.loading; resizeIframe(iframe); }) .catch(function (error) { delete iframe.dataset.loading; // При 401 уже выполняется redirect. if ( error && error.message === 'Session expired' ) { return; } resetIframeObserver(iframe); writeErrorToIframe( iframe, error.message ); console.error( 'Failed to load email:', id, error ); }); } function handleUnauthorized(response) { if (response.status !== 401) { return; } window.location.href = '/login'; throw new Error( 'Session expired' ); } function writeEmailToIframe( iframe, emailBody ) { var doc = iframe.contentWindow.document; doc.open(); doc.write( '' + '' + '' + '' + '' + '' + '' + '' + '' + emailBody + '' + '' ); doc.close(); } function writeErrorToIframe( iframe, message ) { var doc = iframe.contentWindow.document; doc.open(); doc.write( '' + '' + '' + '' + '' + '' + 'Error loading email: ' + escapeHTML(message) + '' + '' ); doc.close(); resizeIframe(iframe); } function resetIframeObserver(iframe) { var observer = iframeObservers.get(iframe); if (observer) { observer.disconnect(); iframeObservers.delete( iframe ); } } function resizeIframe(iframe) { if ( !iframe || !iframe.contentWindow ) { return; } try { var doc = iframe.contentWindow.document; if (!doc || !doc.body) { return; } updateIframeHeight( iframe, doc ); if ( typeof ResizeObserver === 'undefined' ) { return; } var existing = iframeObservers.get(iframe); if (existing) { return; } var observer = new ResizeObserver( function () { try { var currentDoc = iframe .contentWindow .document; updateIframeHeight( iframe, currentDoc ); } catch (error) { // Iframe may have been replaced. } } ); observer.observe( doc.body ); iframeObservers.set( iframe, observer ); } catch (error) { console.warn( 'Cannot resize email iframe:', error ); } } function updateIframeHeight( iframe, doc ) { if (!doc || !doc.body) { return; } var bodyHeight = doc.body.scrollHeight; var htmlHeight = doc.documentElement ? doc.documentElement.scrollHeight : 0; var height = Math.max( bodyHeight, htmlHeight, 180 ); iframe.style.height = height + 20 + 'px'; } function downloadEmail( event, id ) { var button = event.currentTarget; if (!id) { return; } var originalTransform = button.style.transform; var originalOpacity = button.style.opacity; button.disabled = true; button.style.transform = 'scale(0.8)'; button.style.opacity = '0.5'; fetch( '/api/download?id=' + encodeURIComponent(id), { method: 'GET', credentials: 'same-origin' } ) .then(function (response) { handleUnauthorized(response); if (!response.ok) { throw new Error( 'HTTP error ' + response.status ); } return Promise.all([ response.blob(), Promise.resolve( getDownloadFilename( response, id ) ) ]); }) .then(function (result) { var blob = result[0]; var filename = result[1]; var objectURL = URL.createObjectURL(blob); var link = document.createElement('a'); link.href = objectURL; link.download = filename; document.body.appendChild( link ); link.click(); link.remove(); window.setTimeout( function () { URL.revokeObjectURL( objectURL ); }, 1000 ); }) .catch(function (error) { if ( error && error.message === 'Session expired' ) { return; } console.error( 'Failed to download email:', id, error ); window.alert( 'Failed to download email' ); }) .finally(function () { button.disabled = false; button.style.transform = originalTransform; button.style.opacity = originalOpacity; }); } function getDownloadFilename( response, id ) { var contentDisposition = response.headers.get( 'Content-Disposition' ); if (contentDisposition) { var match = contentDisposition.match( /filename="([^"]+)"/i ); if (match && match[1]) { return match[1]; } } var parts = id.split('/'); if (parts.length > 0) { return parts[ parts.length - 1 ]; } return 'email.eml'; } function escapeHTML(value) { return String(value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }