@bobfrankston/rmfmail 1.1.141 → 1.1.143
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 +21 -3
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +28 -3
- package/client/app.js.map +1 -1
- package/client/app.ts +22 -2
- package/client/compose/compose.bundle.js +47 -11
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/compose/compose.js +50 -7
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +37 -7
- package/client/lib/rmf-tiny.js +10 -7
- package/package.json +3 -3
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-39256 → node_modules.npmglobalize-stash-19716}/.package-lock.json +0 -0
package/client/app.ts
CHANGED
|
@@ -949,12 +949,32 @@ async function openCompose(mode: ComposeMode, overrideMsg?: any, overrideAccount
|
|
|
949
949
|
const initJson = JSON.stringify(init);
|
|
950
950
|
try { sessionStorage.setItem("composeInit", initJson); }
|
|
951
951
|
catch (e: any) { console.error("[compose] sessionStorage.setItem failed:", e?.message || e); }
|
|
952
|
+
// Stash on the parent window so a same-origin iframe can pull it via
|
|
953
|
+
// window.parent (most reliable handoff under WebView2 custom-protocol —
|
|
954
|
+
// sessionStorage and postMessage both fail intermittently). Keyed by
|
|
955
|
+
// a unique token in the iframe URL so concurrent composes don't crosswire.
|
|
956
|
+
const composeKey = "init-" + Math.random().toString(36).slice(2, 10);
|
|
957
|
+
(window as any).__mailxComposeInits = (window as any).__mailxComposeInits || {};
|
|
958
|
+
(window as any).__mailxComposeInits[composeKey] = init;
|
|
959
|
+
// Expose the key on the iframe so its IIFE can fetch the right blob.
|
|
960
|
+
try { (frame as any).dataset.composeKey = composeKey; } catch { /* */ }
|
|
952
961
|
const post = (): void => {
|
|
953
|
-
try { frame?.contentWindow?.postMessage({ type: "compose-init", init }, "*"); }
|
|
962
|
+
try { frame?.contentWindow?.postMessage({ type: "compose-init", init, composeKey }, "*"); }
|
|
963
|
+
catch (e: any) { logClientEvent("compose-post-failed", { err: e?.message || String(e) }); }
|
|
954
964
|
};
|
|
965
|
+
logClientEvent("compose-handoff", { hasFrame: !!frame, hasContentWindow: !!frame?.contentWindow, composeKey, bodyBytes: initJson.length });
|
|
955
966
|
post();
|
|
956
967
|
// Iframe may not be loaded yet — re-post on load so the listener exists.
|
|
957
|
-
try { frame?.addEventListener("load",
|
|
968
|
+
try { frame?.addEventListener("load", () => { logClientEvent("compose-iframe-loaded", { composeKey }); post(); }); } catch { /* */ }
|
|
969
|
+
// And keep posting every 100ms for up to 3s as a defense-in-depth — if
|
|
970
|
+
// both load and the initial post race the wrong way, the iframe's IIFE
|
|
971
|
+
// will see the payload on its next tick.
|
|
972
|
+
let attempts = 0;
|
|
973
|
+
const heartbeat = setInterval(() => {
|
|
974
|
+
attempts++;
|
|
975
|
+
post();
|
|
976
|
+
if (attempts >= 30) clearInterval(heartbeat);
|
|
977
|
+
}, 100);
|
|
958
978
|
}
|
|
959
979
|
|
|
960
980
|
function showComposeOverlay(title = "Compose"): HTMLIFrameElement {
|
|
@@ -701,13 +701,16 @@ 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
|
-
// High-contrast caret
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
"body { font-family: system-ui, sans-serif; font-size: 14px; caret-color: #
|
|
704
|
+
// High-contrast caret. Default native bar shape (thin vertical
|
|
705
|
+
// line, browser-drawn — caret-shape:block was too aggressive).
|
|
706
|
+
// Color shifts by ancestor element so the caret doubles as a
|
|
707
|
+
// formatting-mode indicator: blue plain → red bold → green
|
|
708
|
+
// italic → orange underline. Innermost wrapper wins on
|
|
709
|
+
// combinations (em inside strong shows green).
|
|
710
|
+
"body { font-family: system-ui, sans-serif; font-size: 14px; caret-color: #1e88e5; }",
|
|
711
|
+
"b, strong { caret-color: #d32f2f; }",
|
|
712
|
+
"i, em { caret-color: #2e7d32; }",
|
|
713
|
+
"u { caret-color: #ef6c00; }",
|
|
711
714
|
"blockquote { border-left: 3px solid #c0c8d0; margin: 0 0 0 4px; padding: 2px 0 2px 10px; color: #555; }",
|
|
712
715
|
"div.reply { margin-top: 0.5em; }",
|
|
713
716
|
"div.reply > p:first-child { color: #666; font-size: 0.95em; margin: 0 0 4px 0; }",
|
|
@@ -4167,16 +4170,46 @@ function scheduleDraftSave() {
|
|
|
4167
4170
|
var _postedInit = null;
|
|
4168
4171
|
var _parentInitReady = !!sessionStorage.getItem("composeInit");
|
|
4169
4172
|
var _parentInitListeners = [];
|
|
4173
|
+
var _msgEventCount = 0;
|
|
4170
4174
|
window.addEventListener("message", (e) => {
|
|
4175
|
+
_msgEventCount++;
|
|
4171
4176
|
if (e.data?.type === "compose-init-ready") {
|
|
4172
4177
|
_parentInitReady = true;
|
|
4173
4178
|
for (const fn of _parentInitListeners.splice(0)) fn();
|
|
4174
4179
|
} else if (e.data?.type === "compose-init" && e.data.init) {
|
|
4180
|
+
if (!_postedInit) {
|
|
4181
|
+
try {
|
|
4182
|
+
logClientEvent("compose-init-received", { src: "postMessage" });
|
|
4183
|
+
} catch {
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4175
4186
|
_postedInit = e.data.init;
|
|
4176
4187
|
_parentInitReady = true;
|
|
4177
4188
|
for (const fn of _parentInitListeners.splice(0)) fn();
|
|
4178
4189
|
}
|
|
4179
4190
|
});
|
|
4191
|
+
function pullInitFromParent() {
|
|
4192
|
+
try {
|
|
4193
|
+
const myFrame = window.frameElement;
|
|
4194
|
+
const key = myFrame?.dataset?.composeKey;
|
|
4195
|
+
if (!key) return null;
|
|
4196
|
+
const stash = window.parent?.__mailxComposeInits;
|
|
4197
|
+
const init = stash?.[key];
|
|
4198
|
+
if (init) {
|
|
4199
|
+
try {
|
|
4200
|
+
logClientEvent("compose-init-received", { src: "parent-stash", key });
|
|
4201
|
+
} catch {
|
|
4202
|
+
}
|
|
4203
|
+
return init;
|
|
4204
|
+
}
|
|
4205
|
+
} catch (e) {
|
|
4206
|
+
try {
|
|
4207
|
+
logClientEvent("compose-init-pull-failed", { err: e?.message || String(e) });
|
|
4208
|
+
} catch {
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
return null;
|
|
4212
|
+
}
|
|
4180
4213
|
function waitForParentInit(maxMs) {
|
|
4181
4214
|
if (_parentInitReady) return Promise.resolve();
|
|
4182
4215
|
return new Promise((resolve) => {
|
|
@@ -4192,17 +4225,20 @@ function waitForParentInit(maxMs) {
|
|
|
4192
4225
|
}
|
|
4193
4226
|
(async () => {
|
|
4194
4227
|
_ctick("init IIFE start");
|
|
4195
|
-
|
|
4228
|
+
let parentInit = pullInitFromParent();
|
|
4229
|
+
if (!parentInit && !sessionStorage.getItem("composeInit") && !_postedInit) {
|
|
4196
4230
|
_ctick("waiting for parent init");
|
|
4197
4231
|
await waitForParentInit(1500);
|
|
4198
|
-
_ctick(
|
|
4232
|
+
_ctick(`parent init received (msgEvents=${_msgEventCount})`);
|
|
4233
|
+
if (!_postedInit) parentInit = pullInitFromParent();
|
|
4199
4234
|
}
|
|
4200
4235
|
const stored = sessionStorage.getItem("composeInit");
|
|
4201
|
-
const initRaw = _postedInit || (stored ? JSON.parse(stored) : null);
|
|
4236
|
+
const initRaw = parentInit || _postedInit || (stored ? JSON.parse(stored) : null);
|
|
4202
4237
|
if (initRaw) {
|
|
4203
4238
|
sessionStorage.removeItem("composeInit");
|
|
4204
4239
|
const init = initRaw;
|
|
4205
|
-
|
|
4240
|
+
const src = parentInit ? "parent-stash" : _postedInit ? "postMessage" : "sessionStorage";
|
|
4241
|
+
_ctick(`init parsed (mode=${init.mode}, bodyHtml=${init.bodyHtml?.length || 0} bytes, src=${src})`);
|
|
4206
4242
|
if (init.accounts && init.accounts.length > 0) {
|
|
4207
4243
|
applyInit(init);
|
|
4208
4244
|
_ctick("applyInit done \u2014 compose visible");
|