updated layout for webmail

This commit is contained in:
2026-08-15 16:31:27 +01:00
parent f283c90f11
commit 6f0c305367
35 changed files with 2660 additions and 219 deletions
+66 -8
View File
@@ -61,7 +61,7 @@
{{template "csrf_script" .}}
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1090;">
{{range .flashes}}
<div class="toast align-items-center text-bg-{{if eq .Category "error"}}danger{{else}}{{.Category}}{{end}} border-0" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
<div class="toast align-items-center text-bg-{{if eq .Category "error"}}danger{{else}}{{.Category}}{{end}} border-0" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
<i class="bi bi-{{if eq .Category "error"}}exclamation-triangle{{else if eq .Category "success"}}check-circle{{else}}info-circle{{end}} me-2"></i>
@@ -83,6 +83,13 @@
<small class="from-email" id="autosaveStatus" style="display: none;"></small>
<button type="button" id="attachBtn" class="btn btn-outline-light btn-sm" title="Attach files"><i class="bi bi-paperclip"></i></button>
<input type="file" id="attachment_input" name="attachments" multiple style="display: none;">
{{if .signatures}}
<select class="form-select form-select-sm" id="signatureSelect" style="width: auto;" title="Signature">
<option value="">No signature</option>
{{range .signatures}}<option value="{{.ID}}" {{if eq $.default_signature_id .ID}}selected{{end}}>{{.Name}}</option>{{end}}
</select>
{{range .signatures}}<div class="sig-data" data-sig-id="{{.ID}}" style="display: none;">{{.ContentHTML | safe}}</div>{{end}}
{{end}}
<div class="ms-auto d-flex align-items-center gap-2">
{{if .send_as_options}}
<select class="form-select form-select-sm from-select" name="from">
@@ -175,16 +182,67 @@
],
},
});
// Signature tracking: the signature is kept as a plain-paragraph Delta range
// (index/length) rather than a DOM marker div. A wrapping <div> set directly on
// quill.root gets silently discarded by Quill's own MutationObserver within one
// update cycle (it isn't a recognized block type) — confirmed live, so signature
// content is inserted via Quill's own clipboard API instead, which turns it into
// real paragraph blots that survive.
var sigRange = null; // {index, length} of the signature currently in the editor, or null
function insertSignature(index, html) {
if (!html) return null;
const before = quill.getLength();
quill.clipboard.dangerouslyPasteHTML(index, html);
return { index: index, length: quill.getLength() - before };
}
function removeSignature() {
if (sigRange && sigRange.length > 0) quill.deleteText(sigRange.index, sigRange.length);
sigRange = null;
}
(function() {
const seed = document.getElementById('body_html_seed');
if (seed && seed.innerHTML.trim()) {
quill.root.innerHTML = seed.innerHTML;
// Reply/forward seeds start with an empty line above the quoted
// original (see composeCursorHome, webmail_compose.go) — put the
// cursor there so typing starts above the quote, not inside or after it.
quill.setSelection(0, 0);
quill.focus();
if (!seed || !seed.innerHTML.trim()) return;
const parsed = document.createElement('div');
parsed.innerHTML = seed.innerHTML;
const sigEl = parsed.querySelector('#mailSignatureBlock');
let sigHTML = '';
if (sigEl) {
sigHTML = sigEl.innerHTML;
sigEl.remove();
}
quill.root.innerHTML = parsed.innerHTML;
// Reply/forward seeds start with an empty line above the quoted
// original (see composeCursorHome, webmail_compose.go) — put the
// cursor there so typing starts above the quote, not inside or after it.
quill.setSelection(0, 0);
quill.focus();
if (sigHTML) {
// The backend always inserts the signature immediately after that
// leading empty paragraph (index 1), before any quoted/forwarded
// text — see webmailComposeForm.
sigRange = insertSignature(1, sigHTML);
quill.setSelection(0, 0);
}
})();
// Signature picker: swaps the currently-inserted signature (tracked via
// sigRange above) for a different one, or removes it. Picking one when none
// exists yet appends it at the end of the body.
(function() {
const select = document.getElementById('signatureSelect');
if (!select) return;
const sigHTML = {};
document.querySelectorAll('.sig-data').forEach(function(el) { sigHTML[el.dataset.sigId] = el.innerHTML; });
select.addEventListener('change', function() {
const insertAt = sigRange ? sigRange.index : Math.max(0, quill.getLength() - 1);
removeSignature();
if (!select.value) return;
sigRange = insertSignature(insertAt, sigHTML[select.value] || '');
});
})();
// Cc/Bcc start hidden (Outlook-style) unless prefilled (e.g. reply-all sets