@bobfrankston/rmfmail 1.2.329 → 1.2.333
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/android-bootstrap.bundle.js +52 -2
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/compose/compose.bundle.js +66 -6
- package/client/compose/compose.bundle.js.map +3 -3
- package/client/compose/compose.html +3 -0
- package/client/compose/compose.js +75 -4
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +70 -4
- package/client/lib/rmf-tiny.js +34 -4
- package/client/package.json +1 -1
- package/npmchanges.md +9 -0
- package/package.json +3 -3
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +8 -1
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +7 -1
- package/packages/mailx-service/package.json +1 -1
- package/.commitmsg +0 -6
|
@@ -3022,14 +3022,34 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
3022
3022
|
};
|
|
3023
3023
|
reader.readAsDataURL(file);
|
|
3024
3024
|
});
|
|
3025
|
+
const restoreBlobSrcs = (html) => html.replace(/src="(blob:[^"]+)"/g, (m, uri) => {
|
|
3026
|
+
const info = ed.editorUpload?.blobCache?.getByUri?.(uri);
|
|
3027
|
+
return info ? `src="data:${info.blob().type};base64,${info.base64()}"` : m;
|
|
3028
|
+
});
|
|
3025
3029
|
ed.on("GetContent", (e) => {
|
|
3026
3030
|
if (!e?.content || typeof e.content !== "string" || !e.content.includes("blob:"))
|
|
3027
3031
|
return;
|
|
3028
|
-
e.content = e.content
|
|
3029
|
-
const info = ed.editorUpload?.blobCache?.getByUri?.(uri);
|
|
3030
|
-
return info ? `src="data:${info.blob().type};base64,${info.base64()}"` : m;
|
|
3031
|
-
});
|
|
3032
|
+
e.content = restoreBlobSrcs(e.content);
|
|
3032
3033
|
});
|
|
3034
|
+
const copyWithImageData = (e) => {
|
|
3035
|
+
if (!e?.clipboardData)
|
|
3036
|
+
return;
|
|
3037
|
+
let html = "";
|
|
3038
|
+
try {
|
|
3039
|
+
html = ed.selection.getContent({ format: "html" }) || "";
|
|
3040
|
+
} catch {
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
if (!html.includes("blob:"))
|
|
3044
|
+
return;
|
|
3045
|
+
e.preventDefault();
|
|
3046
|
+
e.clipboardData.setData("text/html", restoreBlobSrcs(html));
|
|
3047
|
+
e.clipboardData.setData("text/plain", ed.selection.getContent({ format: "text" }) || "");
|
|
3048
|
+
if (e.type === "cut")
|
|
3049
|
+
ed.execCommand("Delete");
|
|
3050
|
+
};
|
|
3051
|
+
ed.on("copy", copyWithImageData);
|
|
3052
|
+
ed.on("cut", copyWithImageData);
|
|
3033
3053
|
ed.on("OpenWindow", () => {
|
|
3034
3054
|
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
3035
3055
|
const ta = document.querySelector(".tox-dialog textarea");
|
|
@@ -5560,6 +5580,7 @@ async function tryEditor(type) {
|
|
|
5560
5580
|
}
|
|
5561
5581
|
} catch {
|
|
5562
5582
|
}
|
|
5583
|
+
if (ed) wirePasteImageInlining(ed, type);
|
|
5563
5584
|
return ed;
|
|
5564
5585
|
} catch (e) {
|
|
5565
5586
|
logClientEvent("compose-editor-create-failed", { type, error: String(e?.message || e) });
|
|
@@ -5664,6 +5685,17 @@ if (fromInput) {
|
|
|
5664
5685
|
openFromPicker();
|
|
5665
5686
|
});
|
|
5666
5687
|
fromInput.addEventListener("click", openFromPicker);
|
|
5688
|
+
const copyFromBtn = document.getElementById("btn-copy-from");
|
|
5689
|
+
copyFromBtn?.addEventListener("click", async () => {
|
|
5690
|
+
const value = getFromAddress();
|
|
5691
|
+
if (!value) return;
|
|
5692
|
+
try {
|
|
5693
|
+
await navigator.clipboard.writeText(value);
|
|
5694
|
+
showDraftStatus(`Copied From: ${value}`, false);
|
|
5695
|
+
} catch (e) {
|
|
5696
|
+
showDraftStatus(`Copy From failed: ${e?.message || e}`, true);
|
|
5697
|
+
}
|
|
5698
|
+
});
|
|
5667
5699
|
fromInput.addEventListener("blur", () => {
|
|
5668
5700
|
if (fromInput.value.trim() === "" && fromInput.dataset.prevFrom) {
|
|
5669
5701
|
fromInput.value = fromInput.dataset.prevFrom;
|
|
@@ -5817,7 +5849,9 @@ function getFromAccountId() {
|
|
|
5817
5849
|
return def?.id || "";
|
|
5818
5850
|
}
|
|
5819
5851
|
function getFromAddress() {
|
|
5820
|
-
|
|
5852
|
+
const live = fromInput.value.trim();
|
|
5853
|
+
if (live) return live;
|
|
5854
|
+
return (fromInput.dataset.prevFrom || "").trim();
|
|
5821
5855
|
}
|
|
5822
5856
|
function smartTab(current) {
|
|
5823
5857
|
const fields = [toInput, ccInput, bccInput, subjectInput];
|
|
@@ -6388,6 +6422,10 @@ var baselineSnapshot = "";
|
|
|
6388
6422
|
function getContentSnapshot() {
|
|
6389
6423
|
return JSON.stringify({
|
|
6390
6424
|
body: editor?.getHtml() || "",
|
|
6425
|
+
// 2026-09-15 — Claude Code (Fable 5.1). From was not part of the
|
|
6426
|
+
// snapshot, so picking a different identity never triggered a save;
|
|
6427
|
+
// the draft kept the old From until the body or subject changed.
|
|
6428
|
+
from: fromInput ? getFromAddress() : "",
|
|
6391
6429
|
to: toInput?.value || "",
|
|
6392
6430
|
cc: ccInput?.value || "",
|
|
6393
6431
|
bcc: bccInput?.value || "",
|
|
@@ -6478,6 +6516,29 @@ function editorBodyEl() {
|
|
|
6478
6516
|
return document.querySelector(".ql-editor") || document.querySelector(".tt-content .tiptap");
|
|
6479
6517
|
}
|
|
6480
6518
|
var INLINE_CHECKED_ATTR = "data-mailx-inline-checked";
|
|
6519
|
+
function wirePasteImageInlining(ed, type) {
|
|
6520
|
+
const onPaste = () => {
|
|
6521
|
+
const body2 = editorBodyEl();
|
|
6522
|
+
if (!body2) return;
|
|
6523
|
+
for (const img of Array.from(body2.querySelectorAll(`img:not([${INLINE_CHECKED_ATTR}])`))) {
|
|
6524
|
+
img.setAttribute(INLINE_CHECKED_ATTR, "1");
|
|
6525
|
+
}
|
|
6526
|
+
setTimeout(() => {
|
|
6527
|
+
void inlinePastedRemoteImages();
|
|
6528
|
+
}, 50);
|
|
6529
|
+
setTimeout(() => {
|
|
6530
|
+
void inlinePastedRemoteImages();
|
|
6531
|
+
}, 800);
|
|
6532
|
+
};
|
|
6533
|
+
const native = ed?.nativeEditor;
|
|
6534
|
+
if (type === "tinymce" && native?.on) {
|
|
6535
|
+
native.on("paste", onPaste);
|
|
6536
|
+
return;
|
|
6537
|
+
}
|
|
6538
|
+
const body = editorBodyEl();
|
|
6539
|
+
if (body) body.addEventListener("paste", onPaste);
|
|
6540
|
+
else console.error("[compose] paste-image inlining not wired: no editor body");
|
|
6541
|
+
}
|
|
6481
6542
|
async function inlinePastedRemoteImages() {
|
|
6482
6543
|
const body = editorBodyEl();
|
|
6483
6544
|
if (!body) return;
|
|
@@ -6499,7 +6560,6 @@ async function inlinePastedRemoteImages() {
|
|
|
6499
6560
|
}
|
|
6500
6561
|
function scheduleDraftSave() {
|
|
6501
6562
|
markComposeDirty();
|
|
6502
|
-
void inlinePastedRemoteImages();
|
|
6503
6563
|
if (draftDebounceTimer) clearTimeout(draftDebounceTimer);
|
|
6504
6564
|
draftDebounceTimer = setTimeout(() => {
|
|
6505
6565
|
draftDebounceTimer = null;
|