@bobfrankston/rmfmail 1.0.664 → 1.0.666
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/TODO.md +8 -5
- package/bin/build-bundles.mjs +96 -0
- package/client/app.bundle.js +8942 -0
- package/client/app.bundle.js.map +7 -0
- package/client/app.js +69 -2
- package/client/app.js.map +1 -1
- package/client/app.ts +69 -2
- package/client/compose/compose.bundle.js +2872 -0
- package/client/compose/compose.bundle.js.map +7 -0
- package/client/compose/compose.html +5 -1
- package/client/index.html +53 -3
- package/package.json +3 -2
package/client/app.ts
CHANGED
|
@@ -997,7 +997,21 @@ function sanitizeQuotedBody(msg: any): string {
|
|
|
997
997
|
body = body.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
|
|
998
998
|
body = body.replace(/\s+style="[^"]*"/gi, "");
|
|
999
999
|
body = body.replace(/\s+class="[^"]*"/gi, "");
|
|
1000
|
-
|
|
1000
|
+
// Strip layout-table attrs only off non-<img> tags. Earlier this regex
|
|
1001
|
+
// ate width/height on <img> too, which is what made App Store / Play
|
|
1002
|
+
// Store buttons render huge in quoted replies (the source ad had
|
|
1003
|
+
// explicit width="120" height="40" on each image). Q138.
|
|
1004
|
+
body = body.replace(/<(?!img\b)([^>]*?)\s+(width|height|align|valign|bgcolor|cellpadding|cellspacing|border)="[^"]*"([^>]*)>/gi,
|
|
1005
|
+
(_m: string, before: string, _attr: string, after: string) => `<${before}${after}>`);
|
|
1006
|
+
// Loop until no more matches — a single tag with multiple stripped
|
|
1007
|
+
// attrs needs more than one pass since the regex only handles one
|
|
1008
|
+
// attribute per match.
|
|
1009
|
+
let prev = "";
|
|
1010
|
+
while (prev !== body) {
|
|
1011
|
+
prev = body;
|
|
1012
|
+
body = body.replace(/<(?!img\b)([^>]*?)\s+(width|height|align|valign|bgcolor|cellpadding|cellspacing|border)="[^"]*"([^>]*)>/gi,
|
|
1013
|
+
(_m: string, before: string, _attr: string, after: string) => `<${before}${after}>`);
|
|
1014
|
+
}
|
|
1001
1015
|
body = body.replace(/<table[^>]*>/gi, "<div>").replace(/<\/table>/gi, "</div>");
|
|
1002
1016
|
body = body.replace(/<t[rdh][^>]*>/gi, "").replace(/<\/t[rdh]>/gi, " ");
|
|
1003
1017
|
body = body.replace(/<thead[^>]*>|<\/thead>|<tbody[^>]*>|<\/tbody>/gi, "");
|
|
@@ -3762,7 +3776,28 @@ optEditorTiptap?.addEventListener("change", () => {
|
|
|
3762
3776
|
if (optEditorTiptap.checked) saveEditorSetting("tiptap");
|
|
3763
3777
|
});
|
|
3764
3778
|
optEditorTinymce?.addEventListener("change", () => {
|
|
3765
|
-
if (optEditorTinymce.checked)
|
|
3779
|
+
if (optEditorTinymce.checked) {
|
|
3780
|
+
saveEditorSetting("tinymce");
|
|
3781
|
+
// Q133 pre-warm — fire the TinyMCE bundle fetch right now so the
|
|
3782
|
+
// next compose-open finds tinymce.min.js already in WebView2's
|
|
3783
|
+
// HTTP cache. Without this, the first compose after picking
|
|
3784
|
+
// TinyMCE in Settings blocks ~1 s while the bundle downloads.
|
|
3785
|
+
try {
|
|
3786
|
+
// Default points at the locally bundled TinyMCE (build-tinymce.js
|
|
3787
|
+
// copies it from node_modules). Path is relative to index.html
|
|
3788
|
+
// which lives at the client/ root; compose.html (in client/compose/)
|
|
3789
|
+
// uses `../lib/tinymce/...` instead.
|
|
3790
|
+
const cdnUrl = localStorage.getItem("mailx-tinymce-cdn") || "lib/tinymce/tinymce.min.js";
|
|
3791
|
+
// Use <link rel="prefetch"> — fires the request as a hint,
|
|
3792
|
+
// doesn't execute the script (we don't want a stray global
|
|
3793
|
+
// tinymce in the main window; it lives in the compose iframe).
|
|
3794
|
+
const link = document.createElement("link");
|
|
3795
|
+
link.rel = "prefetch";
|
|
3796
|
+
link.as = "script";
|
|
3797
|
+
link.href = cdnUrl;
|
|
3798
|
+
document.head.appendChild(link);
|
|
3799
|
+
} catch { /* prefetch is best-effort */ }
|
|
3800
|
+
}
|
|
3766
3801
|
});
|
|
3767
3802
|
|
|
3768
3803
|
// External editor preference (Edit-in-Word handoff target). Stored under
|
|
@@ -4162,3 +4197,35 @@ if (isApp) {
|
|
|
4162
4197
|
window.addEventListener("beforeunload", sendGeometry);
|
|
4163
4198
|
setInterval(sendGeometry, 60_000);
|
|
4164
4199
|
}
|
|
4200
|
+
|
|
4201
|
+
// Boot-snapshot writer — captures key DOM regions to localStorage so the
|
|
4202
|
+
// next cold start hydrates instantly (see index.html's hydrateFromBootSnapshot).
|
|
4203
|
+
// Saves every 30 s and on beforeunload; pages with no inbox open just save
|
|
4204
|
+
// empty strings, which the loader treats as "skip this region."
|
|
4205
|
+
function saveBootSnapshot(): void {
|
|
4206
|
+
try {
|
|
4207
|
+
const folderTree = document.getElementById("folder-tree");
|
|
4208
|
+
const messageList = document.getElementById("ml-body");
|
|
4209
|
+
const folderTitle = document.getElementById("ml-folder-title");
|
|
4210
|
+
// Only save when at least one region has content. An in-flight render
|
|
4211
|
+
// (e.g. user clicked a folder, list is empty for a tick) would
|
|
4212
|
+
// otherwise clobber the previous good snapshot.
|
|
4213
|
+
const ftHtml = folderTree?.innerHTML?.trim() || "";
|
|
4214
|
+
const mlHtml = messageList?.innerHTML?.trim() || "";
|
|
4215
|
+
if (!ftHtml && !mlHtml) return;
|
|
4216
|
+
const snap = {
|
|
4217
|
+
folderTree: ftHtml,
|
|
4218
|
+
messageList: mlHtml,
|
|
4219
|
+
folderTitle: folderTitle?.innerHTML?.trim() || "",
|
|
4220
|
+
savedAt: Date.now(),
|
|
4221
|
+
};
|
|
4222
|
+
localStorage.setItem("mailx-boot-snapshot", JSON.stringify(snap));
|
|
4223
|
+
} catch { /* best-effort */ }
|
|
4224
|
+
}
|
|
4225
|
+
window.addEventListener("beforeunload", saveBootSnapshot);
|
|
4226
|
+
// Also save when the user tabs away — a Windows kill of an inactive
|
|
4227
|
+
// app would otherwise lose the snapshot up to 30 s old.
|
|
4228
|
+
document.addEventListener("visibilitychange", () => {
|
|
4229
|
+
if (document.visibilityState === "hidden") saveBootSnapshot();
|
|
4230
|
+
});
|
|
4231
|
+
setInterval(saveBootSnapshot, 30_000);
|