MFA fix, added IP blacklist, update webmail client
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
{{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}}
|
||||
Reference in New Issue
Block a user