@bobfrankston/rmfmail 1.2.126 → 1.2.128
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 +40 -1
- package/client/app.bundle.js.map +3 -3
- package/client/app.js +42 -1
- package/client/app.js.map +1 -1
- package/client/app.ts +36 -1
- package/client/compose/compose.bundle.js +45 -1
- package/client/compose/compose.bundle.js.map +3 -3
- package/client/compose/compose.css +4 -1
- package/client/compose/compose.js +68 -1
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +61 -1
- package/client/index.html +1 -0
- package/client/lib/api-client.js +6 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +7 -0
- package/client/lib/mailxapi.js +4 -0
- package/package.json +1 -1
- package/packages/mailx-service/index.d.ts +9 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +28 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +24 -0
- package/packages/mailx-service/jsonrpc.js +2 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -1
- package/packages/mailx-service/jsonrpc.ts +2 -0
package/client/app.ts
CHANGED
|
@@ -994,7 +994,15 @@ async function openCompose(mode: ComposeMode, overrideMsg?: any, overrideAccount
|
|
|
994
994
|
mode === "editAsNew" ? "Edit as new" :
|
|
995
995
|
"Compose";
|
|
996
996
|
const titleSubject = mode === "new" ? "" : (msg?.subject || "");
|
|
997
|
-
const
|
|
997
|
+
const composeTitle = titleSubject ? `${titlePrefix}: ${titleSubject}` : titlePrefix;
|
|
998
|
+
// Default: compose/reply/forward open in their OWN OS window — an
|
|
999
|
+
// overlay covering the message list/preview is the thing Bob wants gone
|
|
1000
|
+
// (2026-07-12 "the default on a reply should just be a separate window
|
|
1001
|
+
// outside the frame"). Overlay remains: small screens, Android (no
|
|
1002
|
+
// popout host), Settings toggle off, or daemon spawn failure.
|
|
1003
|
+
const preferWindow = window.innerWidth > 768 && window.innerHeight > 600
|
|
1004
|
+
&& localStorage.getItem("mailx-compose-in-window") !== "0";
|
|
1005
|
+
let frame: HTMLIFrameElement | null = preferWindow ? null : showComposeOverlay(composeTitle);
|
|
998
1006
|
// Now finish initialisation off the critical path — editor bootstrap
|
|
999
1007
|
// inside the iframe runs concurrently with this await.
|
|
1000
1008
|
const accounts = await accountsP;
|
|
@@ -1202,6 +1210,18 @@ async function openCompose(mode: ComposeMode, overrideMsg?: any, overrideAccount
|
|
|
1202
1210
|
// payload so the iframe can populate even when storage doesn't bridge.
|
|
1203
1211
|
// sessionStorage remains as the fast-path for iframes that finish
|
|
1204
1212
|
// loading before postMessage fires.
|
|
1213
|
+
if (preferWindow && !frame) {
|
|
1214
|
+
try {
|
|
1215
|
+
const { popoutCompose } = await import("./lib/api-client.js");
|
|
1216
|
+
const r = await popoutCompose(init);
|
|
1217
|
+
if (r?.ok) return;
|
|
1218
|
+
console.error("[compose] separate-window open failed — overlay fallback:", r?.reason);
|
|
1219
|
+
} catch (e: any) {
|
|
1220
|
+
console.error("[compose] separate-window open threw — overlay fallback:", e?.message || e);
|
|
1221
|
+
}
|
|
1222
|
+
frame = showComposeOverlay(composeTitle);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1205
1225
|
const initJson = JSON.stringify(init);
|
|
1206
1226
|
try { sessionStorage.setItem("composeInit", initJson); }
|
|
1207
1227
|
catch (e: any) { console.error("[compose] sessionStorage.setItem failed:", e?.message || e); }
|
|
@@ -5254,6 +5274,12 @@ getSettings().then((s: any) => {
|
|
|
5254
5274
|
if (optEditorQuill) optEditorQuill.checked = ed === "quill";
|
|
5255
5275
|
if (optEditorTiptap) optEditorTiptap.checked = ed === "tiptap";
|
|
5256
5276
|
if (optEditorTinymce) optEditorTinymce.checked = ed === "tinymce";
|
|
5277
|
+
const cwEl = document.getElementById("opt-compose-window") as HTMLInputElement | null;
|
|
5278
|
+
if (cwEl) {
|
|
5279
|
+
const inWindow = s.ui?.composeInWindow !== false;
|
|
5280
|
+
cwEl.checked = inWindow;
|
|
5281
|
+
try { localStorage.setItem("mailx-compose-in-window", inWindow ? "1" : "0"); } catch { /* */ }
|
|
5282
|
+
}
|
|
5257
5283
|
const fontEl = document.getElementById("opt-compose-font-size") as HTMLInputElement | null;
|
|
5258
5284
|
if (fontEl) {
|
|
5259
5285
|
const px = Number(s.ui?.composeFontSize);
|
|
@@ -5261,6 +5287,15 @@ getSettings().then((s: any) => {
|
|
|
5261
5287
|
}
|
|
5262
5288
|
}).catch(() => {});
|
|
5263
5289
|
|
|
5290
|
+
document.getElementById("opt-compose-window")?.addEventListener("change", (e) => {
|
|
5291
|
+
const on = (e.target as HTMLInputElement).checked;
|
|
5292
|
+
try { localStorage.setItem("mailx-compose-in-window", on ? "1" : "0"); } catch { /* */ }
|
|
5293
|
+
getSettings().then((settings: any) => {
|
|
5294
|
+
settings.ui = { ...settings.ui, composeInWindow: on };
|
|
5295
|
+
saveSettings(settings);
|
|
5296
|
+
}).catch(() => {});
|
|
5297
|
+
});
|
|
5298
|
+
|
|
5264
5299
|
// Unified compose editing font size (px). Same sync-cache-then-persist shape
|
|
5265
5300
|
// as saveEditorSetting: compose.ts reads `mailx-compose-font-size` from
|
|
5266
5301
|
// localStorage at module load, so the very next compose-open is correct.
|
|
@@ -1043,6 +1043,7 @@ __export(api_client_exports, {
|
|
|
1043
1043
|
deleteTask: () => deleteTask,
|
|
1044
1044
|
drainStoreSync: () => drainStoreSync,
|
|
1045
1045
|
emptyFolder: () => emptyFolder,
|
|
1046
|
+
fetchImageAsDataUri: () => fetchImageAsDataUri,
|
|
1046
1047
|
flagSenderOrDomain: () => flagSenderOrDomain,
|
|
1047
1048
|
formatJsonc: () => formatJsonc,
|
|
1048
1049
|
getAccounts: () => getAccounts,
|
|
@@ -1645,6 +1646,10 @@ function closeComposePopout(id) {
|
|
|
1645
1646
|
const fn = ipc().closeComposePopout;
|
|
1646
1647
|
return fn ? fn(id) : Promise.resolve({ ok: false });
|
|
1647
1648
|
}
|
|
1649
|
+
function fetchImageAsDataUri(url) {
|
|
1650
|
+
const fn = ipc().fetchImageAsDataUri;
|
|
1651
|
+
return fn ? fn(url) : Promise.resolve({ error: "no bridge" });
|
|
1652
|
+
}
|
|
1648
1653
|
async function popoutMainWindow(accountId, folderId, name) {
|
|
1649
1654
|
const fn = ipc().popoutMainWindow;
|
|
1650
1655
|
if (!fn)
|
|
@@ -4049,13 +4054,19 @@ var ccInput = document.getElementById("compose-cc");
|
|
|
4049
4054
|
var bccInput = document.getElementById("compose-bcc");
|
|
4050
4055
|
var subjectInput = document.getElementById("compose-subject");
|
|
4051
4056
|
function autoGrowAddrInput(el) {
|
|
4052
|
-
if (!el) return;
|
|
4057
|
+
if (!el || el.offsetParent === null) return;
|
|
4053
4058
|
el.style.height = "auto";
|
|
4054
4059
|
const max = 8 * 22;
|
|
4055
4060
|
el.style.height = Math.min(el.scrollHeight, max) + "px";
|
|
4056
4061
|
if (el.scrollHeight > max) el.style.overflowY = "auto";
|
|
4057
4062
|
else el.style.overflowY = "hidden";
|
|
4058
4063
|
}
|
|
4064
|
+
function autoGrowAllAddrInputs() {
|
|
4065
|
+
autoGrowAllAddrInputs();
|
|
4066
|
+
requestAnimationFrame(() => requestAnimationFrame(autoGrowAllAddrInputs));
|
|
4067
|
+
setTimeout(autoGrowAllAddrInputs, 250);
|
|
4068
|
+
}
|
|
4069
|
+
window.addEventListener("resize", () => autoGrowAllAddrInputs());
|
|
4059
4070
|
function parseRecipientSegment(seg) {
|
|
4060
4071
|
const s = (seg || "").trim();
|
|
4061
4072
|
if (!s) return null;
|
|
@@ -4786,8 +4797,39 @@ async function saveDraft2() {
|
|
|
4786
4797
|
draftSaving = false;
|
|
4787
4798
|
}
|
|
4788
4799
|
}
|
|
4800
|
+
function editorBodyEl() {
|
|
4801
|
+
const ne = editor?.nativeEditor;
|
|
4802
|
+
if (ne?.getBody) {
|
|
4803
|
+
try {
|
|
4804
|
+
return ne.getBody();
|
|
4805
|
+
} catch {
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
return document.querySelector(".ql-editor") || document.querySelector(".tt-content .tiptap");
|
|
4809
|
+
}
|
|
4810
|
+
var INLINE_CHECKED_ATTR = "data-mailx-inline-checked";
|
|
4811
|
+
async function inlinePastedRemoteImages() {
|
|
4812
|
+
const body = editorBodyEl();
|
|
4813
|
+
if (!body) return;
|
|
4814
|
+
const imgs = Array.from(body.querySelectorAll(`img[src^="http"]:not([${INLINE_CHECKED_ATTR}])`));
|
|
4815
|
+
for (const img of imgs) {
|
|
4816
|
+
img.setAttribute(INLINE_CHECKED_ATTR, "1");
|
|
4817
|
+
const src = img.getAttribute("src") || "";
|
|
4818
|
+
try {
|
|
4819
|
+
const { fetchImageAsDataUri: fetchImageAsDataUri2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
4820
|
+
const r = await fetchImageAsDataUri2(src);
|
|
4821
|
+
if (r?.dataUri) {
|
|
4822
|
+
img.setAttribute("src", r.dataUri);
|
|
4823
|
+
} else if (r?.error) {
|
|
4824
|
+
img.setAttribute("title", `Remote image kept as a link (${r.error})`);
|
|
4825
|
+
}
|
|
4826
|
+
} catch {
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4789
4830
|
function scheduleDraftSave() {
|
|
4790
4831
|
markComposeDirty();
|
|
4832
|
+
void inlinePastedRemoteImages();
|
|
4791
4833
|
if (draftDebounceTimer) clearTimeout(draftDebounceTimer);
|
|
4792
4834
|
draftDebounceTimer = setTimeout(() => {
|
|
4793
4835
|
draftDebounceTimer = null;
|
|
@@ -5219,11 +5261,13 @@ var toggleBccBtn = document.getElementById("btn-toggle-bcc");
|
|
|
5219
5261
|
function setCcVisible(visible) {
|
|
5220
5262
|
ccRow.hidden = !visible;
|
|
5221
5263
|
toggleCcBtn.classList.toggle("active", visible);
|
|
5264
|
+
if (visible) autoGrowAddrInput(ccInput);
|
|
5222
5265
|
if (visible) ccInput.focus();
|
|
5223
5266
|
}
|
|
5224
5267
|
function setBccVisible(visible) {
|
|
5225
5268
|
bccRow.hidden = !visible;
|
|
5226
5269
|
toggleBccBtn.classList.toggle("active", visible);
|
|
5270
|
+
if (visible) autoGrowAddrInput(bccInput);
|
|
5227
5271
|
if (visible) bccInput.focus();
|
|
5228
5272
|
}
|
|
5229
5273
|
toggleCcBtn?.addEventListener("click", () => setCcVisible(!!ccRow.hidden));
|