Files
mailgoserver/internal/webui/templates/webmail_compose_widget.html
T

123 lines
5.4 KiB
HTML

{{define "compose_widget"}}
<div id="composePopup" class="card shadow" style="display: none; position: fixed; z-index: 1080; min-width: 320px; min-height: 200px; resize: none; overflow: hidden; background-color: #2d2d2d; border: 1px solid #404040;">
<div id="composePopupHandle" class="card-header d-flex justify-content-between align-items-center py-1" style="cursor: move; user-select: none;">
<span class="small"><i class="bi bi-pencil-square me-1"></i>Compose</span>
<div>
<button type="button" id="composePopupClose" class="btn btn-sm btn-outline-light border-0 py-0 px-2" title="Close"><i class="bi bi-x-lg"></i></button>
</div>
</div>
<iframe id="composePopupFrame" style="border: 0; width: 100%; flex: 1 1 auto;"></iframe>
<div id="composePopupResize" style="position: absolute; right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize;"></div>
</div>
<script>
// A floating window over the existing /webmail/mail/compose page (loaded as-is
// in an iframe) — Outlook-style compose without rewriting compose itself as a
// modal. Position/size persist in localStorage so it reopens where it was left.
(function() {
const POS_KEY = 'webmail_compose_popup_pos';
const popup = document.getElementById('composePopup');
const handle = document.getElementById('composePopupHandle');
const frame = document.getElementById('composePopupFrame');
const resizeHandle = document.getElementById('composePopupResize');
const closeBtn = document.getElementById('composePopupClose');
function defaultRect() {
const w = Math.min(720, window.innerWidth - 40);
const h = Math.min(600, window.innerHeight - 40);
return { top: Math.max(20, (window.innerHeight - h) / 2), left: Math.max(20, (window.innerWidth - w) / 2), width: w, height: h };
}
function clampRect(r) {
const width = Math.max(320, Math.min(r.width, window.innerWidth - 20));
const height = Math.max(200, Math.min(r.height, window.innerHeight - 20));
const left = Math.max(0, Math.min(r.left, window.innerWidth - width));
const top = Math.max(0, Math.min(r.top, window.innerHeight - height));
return { top, left, width, height };
}
function loadRect() {
try {
const saved = JSON.parse(localStorage.getItem(POS_KEY));
if (saved && typeof saved.top === 'number') return clampRect(saved);
} catch (e) { /* fall through to default */ }
return defaultRect();
}
function saveRect(r) {
localStorage.setItem(POS_KEY, JSON.stringify(r));
}
function applyRect(r) {
popup.style.top = r.top + 'px';
popup.style.left = r.left + 'px';
popup.style.width = r.width + 'px';
popup.style.height = r.height + 'px';
}
function currentRect() {
return {
top: parseFloat(popup.style.top) || 0,
left: parseFloat(popup.style.left) || 0,
width: parseFloat(popup.style.width) || 0,
height: parseFloat(popup.style.height) || 0,
};
}
window.openCompose = function(url) {
applyRect(loadRect());
popup.style.display = 'flex';
popup.style.flexDirection = 'column';
frame.src = url;
};
function closePopup() {
popup.style.display = 'none';
frame.src = 'about:blank';
}
closeBtn.addEventListener('click', closePopup);
// The compose form navigates the iframe on success (send/save-draft both
// redirect away from /mail/compose) — treat that as "done": close the popup
// and refresh the page underneath so the new Sent/Drafts entry shows up.
frame.addEventListener('load', function() {
let path;
try { path = frame.contentWindow.location.pathname; } catch (e) { return; }
if (frame.src === 'about:blank' || path.indexOf('/webmail/mail/compose') !== -1) return;
closePopup();
window.location.reload();
});
let dragOffset = null;
handle.addEventListener('mousedown', function(e) {
if (e.target.closest('button')) return;
const r = popup.getBoundingClientRect();
dragOffset = { x: e.clientX - r.left, y: e.clientY - r.top };
e.preventDefault();
});
let resizing = false;
resizeHandle.addEventListener('mousedown', function(e) {
resizing = true;
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (dragOffset) {
const r = clampRect({ top: e.clientY - dragOffset.y, left: e.clientX - dragOffset.x, width: currentRect().width, height: currentRect().height });
applyRect(r);
} else if (resizing) {
const r = popup.getBoundingClientRect();
const rect = clampRect({ top: r.top, left: r.left, width: e.clientX - r.left, height: e.clientY - r.top });
applyRect(rect);
}
});
document.addEventListener('mouseup', function() {
if (dragOffset || resizing) saveRect(currentRect());
dragOffset = null;
resizing = false;
});
})();
</script>
{{end}}