@bobfrankston/rmfmail 1.1.107 → 1.1.109
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 -9
- package/client/app.js.map +1 -1
- package/client/app.ts +22 -10
- package/client/components/message-viewer.js +4 -0
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +4 -0
- package/client/compose/compose.bundle.js +4 -0
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/lib/api-client.js +5 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +6 -0
- package/package.json +3 -3
- package/packages/mailx-service/index.d.ts +8 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +26 -1
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +28 -0
- package/packages/mailx-service/jsonrpc.js +3 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -1
- package/packages/mailx-service/jsonrpc.ts +3 -0
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-61168 → node_modules.npmglobalize-stash-45836}/.package-lock.json +0 -0
package/client/app.js
CHANGED
|
@@ -7,7 +7,7 @@ import { initMessageList, loadMessages, loadUnifiedInbox, loadSearchResults, rel
|
|
|
7
7
|
import { seenOf, flaggedOf, draftOf, setSeen, setFlagged } from "@bobfrankston/mailx-types";
|
|
8
8
|
import { initTabs, setActiveView as setActiveTabView, openTab } from "./components/tabs.js";
|
|
9
9
|
import { getCurrentMessage, initViewer, popOutCurrentMessage, toggleFullscreenPreview, showPreviewBodyMenu, wrapHtmlBody } from "./components/message-viewer.js";
|
|
10
|
-
import { connectWebSocket, onWsEvent, triggerSync, syncAccount, reauthenticate, getAccounts, getFolders, deleteMessage, deleteMessages, undeleteMessage, restartServer, getSyncPending, getVersion, getSettings, saveSettings, getAutocompleteSettings, saveAutocompleteSettings, repairAccounts, updateFlags, markAsSpamMessages, logClientEvent, sendMessage as apiSendMessage, subscribeStore } from "./lib/api-client.js";
|
|
10
|
+
import { connectWebSocket, onWsEvent, triggerSync, syncAccount, reauthenticate, getAccounts, getFolders, deleteMessage, deleteMessages, undeleteMessage, restartServer, getSyncPending, getVersion, getSettings, saveSettings, getAutocompleteSettings, saveAutocompleteSettings, repairAccounts, updateFlags, markAsSpamMessages, logClientEvent, sendMessage as apiSendMessage, subscribeStore, cancelServerSearch } from "./lib/api-client.js";
|
|
11
11
|
import * as messageState from "./lib/message-state.js";
|
|
12
12
|
// ── New message badge (favicon + title) ──
|
|
13
13
|
/** The user-visible app name. Single point of change for the rename;
|
|
@@ -1282,19 +1282,19 @@ function quoteBody(msg) {
|
|
|
1282
1282
|
const date = new Date(msg.date).toLocaleString();
|
|
1283
1283
|
const from = msg.from.name ? `${msg.from.name} <${msg.from.address}>` : msg.from.address;
|
|
1284
1284
|
const body = sanitizeQuotedBody(msg);
|
|
1285
|
-
// Lead with
|
|
1286
|
-
//
|
|
1287
|
-
//
|
|
1288
|
-
//
|
|
1289
|
-
//
|
|
1290
|
-
return `<p
|
|
1285
|
+
// Lead with an empty paragraph so every editor has a real block for the
|
|
1286
|
+
// caret to land in and the user's reply to flow into — bare <br>s aren't
|
|
1287
|
+
// a block container, so TinyMCE's caret fell through to the quote (Bob
|
|
1288
|
+
// 2026-05-21). The blank-line spacing lives in <br>s AFTER the </p>, not
|
|
1289
|
+
// inside it.
|
|
1290
|
+
return `<p></p><br><br><div class="reply"><p>On ${date}, ${from} wrote:</p><blockquote>${body}</blockquote></div>`;
|
|
1291
1291
|
}
|
|
1292
1292
|
function forwardBody(msg) {
|
|
1293
1293
|
const date = new Date(msg.date).toLocaleString();
|
|
1294
1294
|
const from = msg.from.name ? `${msg.from.name} <${msg.from.address}>` : msg.from.address;
|
|
1295
1295
|
const to = msg.to.map((a) => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
|
|
1296
1296
|
const body = sanitizeQuotedBody(msg);
|
|
1297
|
-
return `<p
|
|
1297
|
+
return `<p></p><br><br><div class="reply"><p>---------- Forwarded message ----------<br>From: ${from}<br>Date: ${date}<br>Subject: ${msg.subject}<br>To: ${to}</p>${body}</div>`;
|
|
1298
1298
|
}
|
|
1299
1299
|
let lastDeleted = null;
|
|
1300
1300
|
let lastMoved = null;
|
|
@@ -2042,11 +2042,14 @@ function doSearch(immediate = false) {
|
|
|
2042
2042
|
const serverOn = !!serverCheck?.checked;
|
|
2043
2043
|
// Any re-run aborts a pending server pass — it'll be rescheduled below
|
|
2044
2044
|
// if still wanted. This is the "editing the search aborts + restarts"
|
|
2045
|
-
// behavior: each keystroke cancels the prior server search.
|
|
2045
|
+
// behavior: each keystroke cancels the prior server search. clearTimeout
|
|
2046
|
+
// kills a not-yet-fired pass; cancelServerSearch() aborts one that's
|
|
2047
|
+
// already mid-sweep on the daemon (generation bump → loop bails).
|
|
2046
2048
|
if (serverSearchTimer) {
|
|
2047
2049
|
clearTimeout(serverSearchTimer);
|
|
2048
2050
|
serverSearchTimer = null;
|
|
2049
2051
|
}
|
|
2052
|
+
cancelServerSearch();
|
|
2050
2053
|
// "This folder" scope: instant client-side filter of the visible rows.
|
|
2051
2054
|
// Only when the server checkbox is OFF — with it on we want the real
|
|
2052
2055
|
// local+server search, not a row filter.
|
|
@@ -2093,6 +2096,7 @@ searchInput?.addEventListener("input", () => {
|
|
|
2093
2096
|
if (serverSearchTimer) {
|
|
2094
2097
|
clearTimeout(serverSearchTimer);
|
|
2095
2098
|
serverSearchTimer = null;
|
|
2099
|
+
cancelServerSearch();
|
|
2096
2100
|
}
|
|
2097
2101
|
updateSearchHighlight();
|
|
2098
2102
|
if (searchInput.value.trim() === "") {
|
|
@@ -2124,6 +2128,7 @@ searchInput?.addEventListener("keydown", (e) => {
|
|
|
2124
2128
|
clearTimeout(serverSearchTimer);
|
|
2125
2129
|
serverSearchTimer = null;
|
|
2126
2130
|
}
|
|
2131
|
+
cancelServerSearch();
|
|
2127
2132
|
updateSearchHighlight();
|
|
2128
2133
|
clearSearchMode();
|
|
2129
2134
|
// Clear any client-side filters
|
|
@@ -4525,6 +4530,17 @@ getSettings().then((s) => {
|
|
|
4525
4530
|
}).catch(() => { });
|
|
4526
4531
|
// Save editor choice to server settings
|
|
4527
4532
|
function saveEditorSetting(editor) {
|
|
4533
|
+
// Update the localStorage cache SYNCHRONOUSLY. compose.ts reads
|
|
4534
|
+
// `mailx-editor-type` from localStorage at module-load to pick the
|
|
4535
|
+
// editor — its async getSettings() refresh only runs when a compose
|
|
4536
|
+
// window opens, and reads localStorage FIRST. Without this write the
|
|
4537
|
+
// cache stays stale and the next compose keeps the old editor until a
|
|
4538
|
+
// full app restart (Bob 2026-05-21: "changed to quill but got tinymce
|
|
4539
|
+
// until I restarted"). With it, the very next compose-open is correct.
|
|
4540
|
+
try {
|
|
4541
|
+
localStorage.setItem("mailx-editor-type", editor);
|
|
4542
|
+
}
|
|
4543
|
+
catch { /* private mode */ }
|
|
4528
4544
|
getSettings().then((settings) => {
|
|
4529
4545
|
settings.ui = { ...settings.ui, editor };
|
|
4530
4546
|
saveSettings(settings);
|