@bobfrankston/rmfmail 1.1.138 → 1.1.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/app.bundle.js +14 -2
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +25 -7
- package/client/app.js.map +1 -1
- package/client/app.ts +18 -7
- package/client/compose/compose.bundle.js +34 -11
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/compose/compose.js +51 -12
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +49 -10
- package/client/lib/rmf-tiny.js +7 -1
- package/package.json +3 -3
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-47880 → node_modules.npmglobalize-stash-43144}/.package-lock.json +0 -0
package/client/app.ts
CHANGED
|
@@ -937,13 +937,24 @@ async function openCompose(mode: ComposeMode, overrideMsg?: any, overrideAccount
|
|
|
937
937
|
}
|
|
938
938
|
|
|
939
939
|
|
|
940
|
-
// Store init data for compose window to pick up.
|
|
941
|
-
//
|
|
942
|
-
//
|
|
943
|
-
//
|
|
944
|
-
//
|
|
945
|
-
|
|
946
|
-
|
|
940
|
+
// Store init data for compose window to pick up. Two parallel paths
|
|
941
|
+
// because sessionStorage propagation to a freshly-loading iframe has
|
|
942
|
+
// intermittently failed under WebView2's custom-protocol host (Bob
|
|
943
|
+
// 2026-05-24: reply-all opened with empty To/Subject; daemon log shows
|
|
944
|
+
// reply-init dump fired correctly but the iframe IIFE saw sessionStorage
|
|
945
|
+
// empty and timed out the wait). postMessage carries the FULL init
|
|
946
|
+
// payload so the iframe can populate even when storage doesn't bridge.
|
|
947
|
+
// sessionStorage remains as the fast-path for iframes that finish
|
|
948
|
+
// loading before postMessage fires.
|
|
949
|
+
const initJson = JSON.stringify(init);
|
|
950
|
+
try { sessionStorage.setItem("composeInit", initJson); }
|
|
951
|
+
catch (e: any) { console.error("[compose] sessionStorage.setItem failed:", e?.message || e); }
|
|
952
|
+
const post = (): void => {
|
|
953
|
+
try { frame?.contentWindow?.postMessage({ type: "compose-init", init }, "*"); } catch { /* */ }
|
|
954
|
+
};
|
|
955
|
+
post();
|
|
956
|
+
// Iframe may not be loaded yet — re-post on load so the listener exists.
|
|
957
|
+
try { frame?.addEventListener("load", post, { once: true }); } catch { /* */ }
|
|
947
958
|
}
|
|
948
959
|
|
|
949
960
|
function showComposeOverlay(title = "Compose"): HTMLIFrameElement {
|
|
@@ -701,7 +701,13 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
701
701
|
// everything else so genuine HTML formatting (bold / italic /
|
|
702
702
|
// tables / inline color) still comes through verbatim.
|
|
703
703
|
content_style: [
|
|
704
|
-
|
|
704
|
+
// High-contrast caret: a 1-2 px slate-coloured I-beam vanishes
|
|
705
|
+
// against white especially on hi-DPI displays. caret-color
|
|
706
|
+
// recolours the native insertion bar; caret-shape:block (CSS
|
|
707
|
+
// UI L4, Chromium 125+) widens it into a solid block. The
|
|
708
|
+
// block falls back to the default bar where unsupported, so
|
|
709
|
+
// the color alone still buys most of the visibility win.
|
|
710
|
+
"body { font-family: system-ui, sans-serif; font-size: 14px; caret-color: #d32f2f; caret-shape: block; }",
|
|
705
711
|
"blockquote { border-left: 3px solid #c0c8d0; margin: 0 0 0 4px; padding: 2px 0 2px 10px; color: #555; }",
|
|
706
712
|
"div.reply { margin-top: 0.5em; }",
|
|
707
713
|
"div.reply > p:first-child { color: #666; font-size: 0.95em; margin: 0 0 4px 0; }",
|
|
@@ -3723,13 +3729,23 @@ function setupAutocomplete(input) {
|
|
|
3723
3729
|
const { start, end } = tokenSpanAtCaret(val, caret);
|
|
3724
3730
|
return val.substring(start, end).trim();
|
|
3725
3731
|
}
|
|
3726
|
-
function replaceCaretToken(replacement) {
|
|
3732
|
+
function replaceCaretToken(replacement, contact) {
|
|
3727
3733
|
const val = input.value;
|
|
3728
3734
|
const caret = input.selectionStart ?? val.length;
|
|
3729
3735
|
const { start, end } = tokenSpanAtCaret(val, caret);
|
|
3730
3736
|
let before = val.substring(0, start);
|
|
3731
|
-
|
|
3737
|
+
let after = val.substring(end);
|
|
3732
3738
|
before = before.replace(/[ \t,]+$/, "");
|
|
3739
|
+
if (contact) {
|
|
3740
|
+
const haystack = `${contact.name} ${contact.email}`.toLowerCase();
|
|
3741
|
+
const stripStranded = (s) => splitRecipients(s).map((p) => p.trim()).filter((p) => p.length > 0 && (p.includes("@") || !haystack.includes(p.toLowerCase()))).join(", ");
|
|
3742
|
+
if (before) before = stripStranded(before);
|
|
3743
|
+
const afterCore = after.replace(/^[\s,]+/, "").replace(/[\s,]+$/, "");
|
|
3744
|
+
if (afterCore) {
|
|
3745
|
+
const cleanedAfter = stripStranded(afterCore);
|
|
3746
|
+
after = cleanedAfter ? ", " + cleanedAfter : "";
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3733
3749
|
const lead = before.length ? ", " : "";
|
|
3734
3750
|
const isLast = after.trim() === "";
|
|
3735
3751
|
const insert = lead + replacement + (isLast ? ", " : "");
|
|
@@ -3812,7 +3828,7 @@ function setupAutocomplete(input) {
|
|
|
3812
3828
|
e.preventDefault();
|
|
3813
3829
|
if (e.button !== 0) return;
|
|
3814
3830
|
const display = formatRecipient(r.name, r.email);
|
|
3815
|
-
replaceCaretToken(display);
|
|
3831
|
+
replaceCaretToken(display, { name: r.name, email: r.email });
|
|
3816
3832
|
});
|
|
3817
3833
|
item.addEventListener("contextmenu", (e) => {
|
|
3818
3834
|
e.preventDefault();
|
|
@@ -4148,12 +4164,18 @@ function scheduleDraftSave() {
|
|
|
4148
4164
|
});
|
|
4149
4165
|
}, DRAFT_INPUT_DEBOUNCE_MS);
|
|
4150
4166
|
}
|
|
4167
|
+
var _postedInit = null;
|
|
4151
4168
|
var _parentInitReady = !!sessionStorage.getItem("composeInit");
|
|
4152
4169
|
var _parentInitListeners = [];
|
|
4153
4170
|
window.addEventListener("message", (e) => {
|
|
4154
|
-
if (e.data?.type
|
|
4155
|
-
|
|
4156
|
-
|
|
4171
|
+
if (e.data?.type === "compose-init-ready") {
|
|
4172
|
+
_parentInitReady = true;
|
|
4173
|
+
for (const fn of _parentInitListeners.splice(0)) fn();
|
|
4174
|
+
} else if (e.data?.type === "compose-init" && e.data.init) {
|
|
4175
|
+
_postedInit = e.data.init;
|
|
4176
|
+
_parentInitReady = true;
|
|
4177
|
+
for (const fn of _parentInitListeners.splice(0)) fn();
|
|
4178
|
+
}
|
|
4157
4179
|
});
|
|
4158
4180
|
function waitForParentInit(maxMs) {
|
|
4159
4181
|
if (_parentInitReady) return Promise.resolve();
|
|
@@ -4170,16 +4192,17 @@ function waitForParentInit(maxMs) {
|
|
|
4170
4192
|
}
|
|
4171
4193
|
(async () => {
|
|
4172
4194
|
_ctick("init IIFE start");
|
|
4173
|
-
if (!sessionStorage.getItem("composeInit")) {
|
|
4195
|
+
if (!sessionStorage.getItem("composeInit") && !_postedInit) {
|
|
4174
4196
|
_ctick("waiting for parent init");
|
|
4175
4197
|
await waitForParentInit(1500);
|
|
4176
4198
|
_ctick("parent init received");
|
|
4177
4199
|
}
|
|
4178
4200
|
const stored = sessionStorage.getItem("composeInit");
|
|
4179
|
-
|
|
4201
|
+
const initRaw = _postedInit || (stored ? JSON.parse(stored) : null);
|
|
4202
|
+
if (initRaw) {
|
|
4180
4203
|
sessionStorage.removeItem("composeInit");
|
|
4181
|
-
const init =
|
|
4182
|
-
_ctick(`init parsed (mode=${init.mode}, bodyHtml=${init.bodyHtml?.length || 0} bytes)`);
|
|
4204
|
+
const init = initRaw;
|
|
4205
|
+
_ctick(`init parsed (mode=${init.mode}, bodyHtml=${init.bodyHtml?.length || 0} bytes, src=${_postedInit ? "postMessage" : "sessionStorage"})`);
|
|
4183
4206
|
if (init.accounts && init.accounts.length > 0) {
|
|
4184
4207
|
applyInit(init);
|
|
4185
4208
|
_ctick("applyInit done \u2014 compose visible");
|