123 lines
5.4 KiB
HTML
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}}
|