@bobfrankston/rmfmail 1.0.681 → 1.0.686
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/bin/lean-accounts.js +0 -1
- package/client/app.bundle.js +138 -38
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +12 -1
- package/client/app.js.map +1 -1
- package/client/app.ts +12 -1
- package/client/components/context-menu.js +2 -0
- package/client/components/context-menu.js.map +1 -1
- package/client/components/context-menu.ts +6 -0
- package/client/components/folder-tree.js +26 -4
- package/client/components/folder-tree.js.map +1 -1
- package/client/components/folder-tree.ts +21 -4
- package/client/components/message-list.js +108 -40
- package/client/components/message-list.js.map +1 -1
- package/client/components/message-list.ts +103 -38
- package/client/compose/compose.bundle.js +148 -15
- package/client/compose/compose.bundle.js.map +3 -3
- package/client/compose/spellcheck.js +178 -12
- package/client/compose/spellcheck.js.map +1 -1
- package/client/compose/spellcheck.ts +168 -8
- package/client/lib/api-client.js +3 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +4 -0
- package/client/lib/mailxapi.js +3 -0
- package/client/lib/rmf-tiny.js +25 -6
- package/package.json +7 -7
- package/packages/mailx-core/index.d.ts.map +1 -1
- package/packages/mailx-core/index.js +2 -12
- package/packages/mailx-core/index.js.map +1 -1
- package/packages/mailx-core/index.ts +2 -12
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +31 -6
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +32 -6
- package/packages/mailx-imap/node_modules.npmglobalize-stash-11884/.package-lock.json +116 -0
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts +22 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +123 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +109 -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-service/local-store.d.ts.map +1 -1
- package/packages/mailx-service/local-store.js +6 -12
- package/packages/mailx-service/local-store.js.map +1 -1
- package/packages/mailx-service/local-store.ts +6 -12
- package/packages/mailx-settings/docs/accounts.md +14 -1
- package/packages/mailx-settings/docs/npmglobalize-disttag.md +90 -0
- package/packages/mailx-settings/docs/prod-android.md +88 -0
- package/packages/mailx-settings/docs/prod.md +224 -0
- package/packages/mailx-settings/docs/push-relay.md +141 -0
- package/packages/mailx-settings/docs/rmf-tiny.md +156 -0
- package/packages/mailx-settings/index.d.ts +1 -1
- package/packages/mailx-settings/index.d.ts.map +1 -1
- package/packages/mailx-settings/index.js +1 -4
- package/packages/mailx-settings/index.js.map +1 -1
- package/packages/mailx-settings/index.ts +1 -3
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/db.d.ts.map +1 -1
- package/packages/mailx-store/db.js +44 -6
- package/packages/mailx-store/db.js.map +1 -1
- package/packages/mailx-store/db.ts +47 -6
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store-web/package.json +4 -1
- package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
- package/packages/mailx-store-web/web-settings.js +0 -1
- package/packages/mailx-store-web/web-settings.js.map +1 -1
- package/packages/mailx-store-web/web-settings.ts +0 -1
- package/packages/mailx-types/index.d.ts +1 -2
- package/packages/mailx-types/index.d.ts.map +1 -1
- package/packages/mailx-types/index.js.map +1 -1
- package/packages/mailx-types/index.ts +1 -2
- package/packages/mailx-types/package.json +1 -1
|
@@ -85,6 +85,7 @@ __export(api_client_exports, {
|
|
|
85
85
|
logClientEvent: () => logClientEvent,
|
|
86
86
|
markAsSpamMessages: () => markAsSpamMessages,
|
|
87
87
|
markFolderRead: () => markFolderRead,
|
|
88
|
+
moveFolderToTrash: () => moveFolderToTrash,
|
|
88
89
|
moveMessage: () => moveMessage,
|
|
89
90
|
moveMessages: () => moveMessages,
|
|
90
91
|
onEvent: () => onEvent,
|
|
@@ -357,6 +358,9 @@ function renameFolder(accountId, folderId, newName) {
|
|
|
357
358
|
function deleteFolder(accountId, folderId) {
|
|
358
359
|
return ipc().deleteFolder?.(accountId, folderId);
|
|
359
360
|
}
|
|
361
|
+
function moveFolderToTrash(accountId, folderId) {
|
|
362
|
+
return ipc().moveFolderToTrash?.(accountId, folderId);
|
|
363
|
+
}
|
|
360
364
|
function emptyFolder(accountId, folderId) {
|
|
361
365
|
return ipc().emptyFolder?.(accountId, folderId);
|
|
362
366
|
}
|
|
@@ -617,7 +621,23 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
617
621
|
return;
|
|
618
622
|
args.content = args.content.replace(/(^|[\s(\[])((?:https?|ftp):\/\/[^\s<>"']+[^\s<>"'.,;:!?)\]])/gi, (_m, lead, url) => `${lead}<a href="${url}">${url}</a>`);
|
|
619
623
|
},
|
|
620
|
-
|
|
624
|
+
// Body font + quoted-reply styling. Without explicit rules for
|
|
625
|
+
// <blockquote> and div.reply the editor iframe renders the
|
|
626
|
+
// quoted block with no visual distinction from the user's own
|
|
627
|
+
// text — pasted reply quotes vanish into a wall of unformatted
|
|
628
|
+
// paragraphs (Bob 2026-05-12: "the body losing all formatting").
|
|
629
|
+
// The styles below match Thunderbird/Outlook conventions: a
|
|
630
|
+
// muted left-bar + indent on blockquotes, slight color shift on
|
|
631
|
+
// the "On … wrote:" attribution, untouched typography for
|
|
632
|
+
// everything else so genuine HTML formatting (bold / italic /
|
|
633
|
+
// tables / inline color) still comes through verbatim.
|
|
634
|
+
content_style: [
|
|
635
|
+
"body { font-family: system-ui, sans-serif; font-size: 14px; }",
|
|
636
|
+
"blockquote { border-left: 3px solid #c0c8d0; margin: 0 0 0 4px; padding: 2px 0 2px 10px; color: #555; }",
|
|
637
|
+
"div.reply { margin-top: 0.5em; }",
|
|
638
|
+
"div.reply > p:first-child { color: #666; font-size: 0.95em; margin: 0 0 4px 0; }",
|
|
639
|
+
"pre, code { font-family: ui-monospace, Consolas, Menlo, monospace; }"
|
|
640
|
+
].join(" "),
|
|
621
641
|
init_instance_callback: (ed) => resolve(ed),
|
|
622
642
|
setup: (ed) => {
|
|
623
643
|
if (opts.initialHtml)
|
|
@@ -714,10 +734,14 @@ async function createTinyMceEditor(container2, opts = {}) {
|
|
|
714
734
|
focus() {
|
|
715
735
|
editor2.focus();
|
|
716
736
|
},
|
|
717
|
-
setCursor(
|
|
737
|
+
setCursor(pos) {
|
|
718
738
|
try {
|
|
719
739
|
editor2.selection.select(editor2.getBody(), true);
|
|
720
|
-
editor2.selection.collapse(
|
|
740
|
+
editor2.selection.collapse(
|
|
741
|
+
pos === 0
|
|
742
|
+
/* true = start */
|
|
743
|
+
);
|
|
744
|
+
editor2.focus();
|
|
721
745
|
} catch {
|
|
722
746
|
}
|
|
723
747
|
},
|
|
@@ -1766,7 +1790,7 @@ function decorate(editor2, sp) {
|
|
|
1766
1790
|
p = p.parentNode;
|
|
1767
1791
|
}
|
|
1768
1792
|
}
|
|
1769
|
-
const
|
|
1793
|
+
const savedAbs = caretAbsOffsetFromBody(body);
|
|
1770
1794
|
try {
|
|
1771
1795
|
editor2.undoManager?.ignore?.(() => {
|
|
1772
1796
|
const old = body.querySelectorAll(`span[${MARKER_ATTR}]`);
|
|
@@ -1791,6 +1815,16 @@ function decorate(editor2, sp) {
|
|
|
1791
1815
|
return NodeFilter.FILTER_ACCEPT;
|
|
1792
1816
|
}
|
|
1793
1817
|
});
|
|
1818
|
+
let caretNode = null;
|
|
1819
|
+
let caretOffset = 0;
|
|
1820
|
+
const liveSel = doc.getSelection();
|
|
1821
|
+
if (liveSel && liveSel.rangeCount > 0) {
|
|
1822
|
+
const f = liveSel.focusNode;
|
|
1823
|
+
if (f && f.nodeType === Node.TEXT_NODE) {
|
|
1824
|
+
caretNode = f;
|
|
1825
|
+
caretOffset = liveSel.focusOffset;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1794
1828
|
const hits = [];
|
|
1795
1829
|
let n = walker.nextNode();
|
|
1796
1830
|
const WORD_RE = /[\p{L}][\p{L}'’\-]*/gu;
|
|
@@ -1803,6 +1837,9 @@ function decorate(editor2, sp) {
|
|
|
1803
1837
|
const word = m[0];
|
|
1804
1838
|
if (word.length < MIN_WORD_LEN)
|
|
1805
1839
|
continue;
|
|
1840
|
+
if (caretNode === tn && caretOffset >= m.index && caretOffset <= m.index + word.length) {
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1806
1843
|
if (sp.correct(word))
|
|
1807
1844
|
continue;
|
|
1808
1845
|
hits.push({ node: tn, start: m.index, end: m.index + word.length });
|
|
@@ -1823,11 +1860,72 @@ function decorate(editor2, sp) {
|
|
|
1823
1860
|
}
|
|
1824
1861
|
});
|
|
1825
1862
|
} finally {
|
|
1826
|
-
if (
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1863
|
+
if (savedAbs != null)
|
|
1864
|
+
restoreCaretFromAbsOffset(body, savedAbs);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
function caretAbsOffsetFromBody(body) {
|
|
1868
|
+
const doc = body.ownerDocument;
|
|
1869
|
+
const sel = doc.getSelection();
|
|
1870
|
+
if (!sel || sel.rangeCount === 0)
|
|
1871
|
+
return null;
|
|
1872
|
+
const focusNode = sel.focusNode;
|
|
1873
|
+
const focusOffset = sel.focusOffset;
|
|
1874
|
+
if (!focusNode)
|
|
1875
|
+
return null;
|
|
1876
|
+
if (focusNode.nodeType !== Node.TEXT_NODE) {
|
|
1877
|
+
let abs2 = 0;
|
|
1878
|
+
const walker2 = doc.createTreeWalker(body, NodeFilter.SHOW_TEXT);
|
|
1879
|
+
let n2 = walker2.nextNode();
|
|
1880
|
+
while (n2) {
|
|
1881
|
+
if (focusNode.contains(n2))
|
|
1882
|
+
break;
|
|
1883
|
+
const cmp = focusNode.compareDocumentPosition(n2);
|
|
1884
|
+
if (cmp & Node.DOCUMENT_POSITION_PRECEDING)
|
|
1885
|
+
abs2 += n2.data.length;
|
|
1886
|
+
n2 = walker2.nextNode();
|
|
1887
|
+
}
|
|
1888
|
+
return abs2;
|
|
1889
|
+
}
|
|
1890
|
+
let abs = 0;
|
|
1891
|
+
const walker = doc.createTreeWalker(body, NodeFilter.SHOW_TEXT);
|
|
1892
|
+
let n = walker.nextNode();
|
|
1893
|
+
while (n) {
|
|
1894
|
+
if (n === focusNode)
|
|
1895
|
+
return abs + focusOffset;
|
|
1896
|
+
abs += n.data.length;
|
|
1897
|
+
n = walker.nextNode();
|
|
1898
|
+
}
|
|
1899
|
+
return null;
|
|
1900
|
+
}
|
|
1901
|
+
function restoreCaretFromAbsOffset(body, abs) {
|
|
1902
|
+
const doc = body.ownerDocument;
|
|
1903
|
+
const sel = doc.getSelection();
|
|
1904
|
+
if (!sel)
|
|
1905
|
+
return;
|
|
1906
|
+
const walker = doc.createTreeWalker(body, NodeFilter.SHOW_TEXT);
|
|
1907
|
+
let acc = 0;
|
|
1908
|
+
let n = walker.nextNode();
|
|
1909
|
+
while (n) {
|
|
1910
|
+
const len = n.data.length;
|
|
1911
|
+
if (acc + len >= abs) {
|
|
1912
|
+
const range = doc.createRange();
|
|
1913
|
+
range.setStart(n, Math.max(0, abs - acc));
|
|
1914
|
+
range.collapse(true);
|
|
1915
|
+
sel.removeAllRanges();
|
|
1916
|
+
sel.addRange(range);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
acc += len;
|
|
1920
|
+
n = walker.nextNode();
|
|
1921
|
+
}
|
|
1922
|
+
const last = walker.previousNode();
|
|
1923
|
+
if (last) {
|
|
1924
|
+
const range = doc.createRange();
|
|
1925
|
+
range.setStart(last, last.data.length);
|
|
1926
|
+
range.collapse(true);
|
|
1927
|
+
sel.removeAllRanges();
|
|
1928
|
+
sel.addRange(range);
|
|
1831
1929
|
}
|
|
1832
1930
|
}
|
|
1833
1931
|
function installDecorationStyle(editor2) {
|
|
@@ -1920,18 +2018,37 @@ function showSuggestionsMenu(parentDoc, x, y, items) {
|
|
|
1920
2018
|
menu.style.left = `${Math.max(8, window.innerWidth - r.width - 8)}px`;
|
|
1921
2019
|
if (r.bottom > window.innerHeight)
|
|
1922
2020
|
menu.style.top = `${Math.max(8, window.innerHeight - r.height - 8)}px`;
|
|
2021
|
+
const docs = [parentDoc];
|
|
2022
|
+
try {
|
|
2023
|
+
const composeWin = parentDoc.defaultView;
|
|
2024
|
+
if (composeWin?.frameElement && composeWin.parent?.document && composeWin.parent.document !== parentDoc) {
|
|
2025
|
+
docs.push(composeWin.parent.document);
|
|
2026
|
+
}
|
|
2027
|
+
} catch {
|
|
2028
|
+
}
|
|
2029
|
+
try {
|
|
2030
|
+
const editorIframe = parentDoc.querySelector("iframe.tox-edit-area__iframe") || parentDoc.querySelector("iframe");
|
|
2031
|
+
const editorDoc = editorIframe?.contentDocument;
|
|
2032
|
+
if (editorDoc && editorDoc !== parentDoc)
|
|
2033
|
+
docs.push(editorDoc);
|
|
2034
|
+
} catch {
|
|
2035
|
+
}
|
|
1923
2036
|
const dismiss2 = (e) => {
|
|
1924
2037
|
if (e.type === "keydown" && e.key !== "Escape")
|
|
1925
2038
|
return;
|
|
1926
2039
|
if (e.type === "mousedown" && menu.contains(e.target))
|
|
1927
2040
|
return;
|
|
1928
2041
|
menu.remove();
|
|
1929
|
-
|
|
1930
|
-
|
|
2042
|
+
for (const d of docs) {
|
|
2043
|
+
d.removeEventListener("mousedown", dismiss2, true);
|
|
2044
|
+
d.removeEventListener("keydown", dismiss2, true);
|
|
2045
|
+
}
|
|
1931
2046
|
};
|
|
1932
2047
|
setTimeout(() => {
|
|
1933
|
-
|
|
1934
|
-
|
|
2048
|
+
for (const d of docs) {
|
|
2049
|
+
d.addEventListener("mousedown", dismiss2, true);
|
|
2050
|
+
d.addEventListener("keydown", dismiss2, true);
|
|
2051
|
+
}
|
|
1935
2052
|
}, 0);
|
|
1936
2053
|
}
|
|
1937
2054
|
function replaceMarker(editor2, marker, replacement) {
|
|
@@ -1993,7 +2110,21 @@ function wireSpellcheck(editor2) {
|
|
|
1993
2110
|
return;
|
|
1994
2111
|
e.preventDefault();
|
|
1995
2112
|
e.stopPropagation();
|
|
1996
|
-
const
|
|
2113
|
+
const transposed = [];
|
|
2114
|
+
for (let i = 0; i < word.length - 1; i++) {
|
|
2115
|
+
const swapped = word.slice(0, i) + word[i + 1] + word[i] + word.slice(i + 2);
|
|
2116
|
+
if (swapped !== word && sp.correct(swapped) && !transposed.includes(swapped)) {
|
|
2117
|
+
transposed.push(swapped);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
const nspellSugs = sp.suggest(word);
|
|
2121
|
+
const sugs = [];
|
|
2122
|
+
for (const s of [...transposed, ...nspellSugs]) {
|
|
2123
|
+
if (!sugs.includes(s))
|
|
2124
|
+
sugs.push(s);
|
|
2125
|
+
if (sugs.length >= 7)
|
|
2126
|
+
break;
|
|
2127
|
+
}
|
|
1997
2128
|
const iframeEl = editor2.iframeElement;
|
|
1998
2129
|
const iframeRect = iframeEl ? iframeEl.getBoundingClientRect() : { left: 0, top: 0 };
|
|
1999
2130
|
const items = [];
|
|
@@ -2040,7 +2171,7 @@ var init_spellcheck = __esm({
|
|
|
2040
2171
|
import_nspell = __toESM(require_lib(), 1);
|
|
2041
2172
|
USER_DICT_KEY = "mailx-user-dict";
|
|
2042
2173
|
MARKER_ATTR = "data-mailx-spellerror";
|
|
2043
|
-
DECORATE_DEBOUNCE_MS =
|
|
2174
|
+
DECORATE_DEBOUNCE_MS = 1200;
|
|
2044
2175
|
MIN_WORD_LEN = 3;
|
|
2045
2176
|
SKIP_TAGS = /* @__PURE__ */ new Set(["BLOCKQUOTE", "CODE", "PRE", "A", "SCRIPT", "STYLE", "KBD", "SAMP", "VAR"]);
|
|
2046
2177
|
spellPromise = null;
|
|
@@ -2922,6 +3053,8 @@ function showContextMenu(x, y, items) {
|
|
|
2922
3053
|
const el = document.createElement("div");
|
|
2923
3054
|
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
|
|
2924
3055
|
el.textContent = item.label;
|
|
3056
|
+
if (item.tooltip)
|
|
3057
|
+
el.title = item.tooltip;
|
|
2925
3058
|
if (!item.disabled) {
|
|
2926
3059
|
el.addEventListener("click", () => {
|
|
2927
3060
|
closeContextMenu();
|