@bobfrankston/rmfmail 1.2.221 → 1.2.223
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/mailx.js +27 -18
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +28 -18
- package/client/app.bundle.js +79 -1
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +21 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +21 -0
- package/client/components/context-menu.js +76 -0
- package/client/components/context-menu.js.map +1 -1
- package/client/components/context-menu.ts +77 -0
- package/client/compose/compose.bundle.js +281 -57
- package/client/compose/compose.bundle.js.map +4 -4
- package/client/compose/compose.js +4 -59
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +4 -32
- package/client/compose/edit-commands.js +207 -0
- package/client/compose/edit-commands.js.map +1 -0
- package/client/compose/edit-commands.ts +181 -0
- package/client/compose/editor.js +6 -0
- package/client/compose/editor.js.map +1 -1
- package/client/compose/editor.ts +6 -0
- package/client/compose/spellcheck.js +19 -0
- package/client/compose/spellcheck.js.map +1 -1
- package/client/compose/spellcheck.ts +11 -0
- package/client/lib/rmf-tiny.js +7 -1
- package/package.json +3 -3
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-39780 → node_modules.npmglobalize-stash-65000}/.package-lock.json +0 -0
package/bin/mailx.ts
CHANGED
|
@@ -183,6 +183,32 @@ const isDaemon = hasFlag("daemon"); // internal: re-spawned detached process
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/** App entries appended to the NATIVE right-click menu inside compose. msger
|
|
187
|
+
* keeps the WebView2 default menu (that is the only place spellcheck
|
|
188
|
+
* suggestions live) and gates these to editable targets, so they never show
|
|
189
|
+
* on the read-only list or message preview.
|
|
190
|
+
*
|
|
191
|
+
* Deliberately NO Cut/Copy/Paste here: WebView2's own menu already carries
|
|
192
|
+
* them (with the right enabled/disabled state and the Ctrl+X/C/V hints), so
|
|
193
|
+
* app copies would just be duplicates a few rows further down. The menu that
|
|
194
|
+
* genuinely lacks them is mailx's spell menu, which preventDefaults the
|
|
195
|
+
* native one away — that gap is filled in compose/edit-commands.ts, at the
|
|
196
|
+
* menu that actually has the hole (Bob 2026-08-07).
|
|
197
|
+
*
|
|
198
|
+
* Ids are dispatched to compose.ts via window.__msgerContextCommand — one
|
|
199
|
+
* list, both windows (in-window compose overlay + popout compose), because
|
|
200
|
+
* drift between the two is what produced "right mouse isn't showing any
|
|
201
|
+
* formatting options" in the first place (Bob 2026-07-18). */
|
|
202
|
+
const COMPOSE_CONTEXT_MENU_ITEMS = [
|
|
203
|
+
{ id: "bold", label: "Bold" },
|
|
204
|
+
{ id: "italic", label: "Italic" },
|
|
205
|
+
{ id: "underline", label: "Underline" },
|
|
206
|
+
{ id: "strike", label: "Strikethrough" },
|
|
207
|
+
{ id: "link", label: "Link…" },
|
|
208
|
+
{ id: "clear", label: "Clear formatting" },
|
|
209
|
+
{ id: "source", label: "View HTML source…" },
|
|
210
|
+
];
|
|
211
|
+
|
|
186
212
|
/** Windows mailto: registration — registry keys via reg.exe. Shared by the
|
|
187
213
|
* `-register-mailto` CLI flag and the Settings → "Make default email app"
|
|
188
214
|
* menu action (injected into MailxService; the registry work stays HERE in
|
|
@@ -2420,15 +2446,7 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
|
|
|
2420
2446
|
// App entries on the NATIVE right-click menu (native stays
|
|
2421
2447
|
// so spellcheck suggestions survive). compose.ts maps ids
|
|
2422
2448
|
// to editor commands via window.__msgerContextCommand.
|
|
2423
|
-
contextMenuItems:
|
|
2424
|
-
{ id: "bold", label: "Bold" },
|
|
2425
|
-
{ id: "italic", label: "Italic" },
|
|
2426
|
-
{ id: "underline", label: "Underline" },
|
|
2427
|
-
{ id: "strike", label: "Strikethrough" },
|
|
2428
|
-
{ id: "link", label: "Link…" },
|
|
2429
|
-
{ id: "clear", label: "Clear formatting" },
|
|
2430
|
-
{ id: "source", label: "View HTML source…" },
|
|
2431
|
-
],
|
|
2449
|
+
contextMenuItems: COMPOSE_CONTEXT_MENU_ITEMS,
|
|
2432
2450
|
});
|
|
2433
2451
|
popoutWindows.set(key, h);
|
|
2434
2452
|
if (typeof h.pid === "number") addChildPid(h.pid);
|
|
@@ -2552,15 +2570,7 @@ RFC 5322 with CRLF line endings. Bodies are quoted-printable encoded (readable i
|
|
|
2552
2570
|
// "right mouse isn't showing any formatting options let alone source").
|
|
2553
2571
|
// msger gates these to editable targets, so they DON'T appear on
|
|
2554
2572
|
// right-clicks in the read-only list / message preview.
|
|
2555
|
-
contextMenuItems:
|
|
2556
|
-
{ id: "bold", label: "Bold" },
|
|
2557
|
-
{ id: "italic", label: "Italic" },
|
|
2558
|
-
{ id: "underline", label: "Underline" },
|
|
2559
|
-
{ id: "strike", label: "Strikethrough" },
|
|
2560
|
-
{ id: "link", label: "Link…" },
|
|
2561
|
-
{ id: "clear", label: "Clear formatting" },
|
|
2562
|
-
{ id: "source", label: "View HTML source…" },
|
|
2563
|
-
],
|
|
2573
|
+
contextMenuItems: COMPOSE_CONTEXT_MENU_ITEMS,
|
|
2564
2574
|
});
|
|
2565
2575
|
// Late-bind the popout-action forwarder now that the main window's
|
|
2566
2576
|
// service channel exists.
|
package/client/app.bundle.js
CHANGED
|
@@ -723,7 +723,14 @@ __export(context_menu_exports, {
|
|
|
723
723
|
closeContextMenu: () => closeContextMenu,
|
|
724
724
|
showContextMenu: () => showContextMenu
|
|
725
725
|
});
|
|
726
|
+
function closeSubmenu() {
|
|
727
|
+
if (activeSubmenu) {
|
|
728
|
+
activeSubmenu.remove();
|
|
729
|
+
activeSubmenu = null;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
726
732
|
function closeContextMenu() {
|
|
733
|
+
closeSubmenu();
|
|
727
734
|
if (activeMenu) {
|
|
728
735
|
activeMenu.remove();
|
|
729
736
|
activeMenu = null;
|
|
@@ -737,6 +744,45 @@ function closeContextMenu() {
|
|
|
737
744
|
escapeListener = null;
|
|
738
745
|
}
|
|
739
746
|
}
|
|
747
|
+
function openSubmenu(parentRow, items) {
|
|
748
|
+
closeSubmenu();
|
|
749
|
+
const sub = document.createElement("div");
|
|
750
|
+
sub.className = "ctx-menu";
|
|
751
|
+
for (const item of items) {
|
|
752
|
+
if (item.separator) {
|
|
753
|
+
const sep = document.createElement("div");
|
|
754
|
+
sep.className = "ctx-sep";
|
|
755
|
+
sub.appendChild(sep);
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
const el = document.createElement("div");
|
|
759
|
+
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
|
|
760
|
+
el.textContent = item.label;
|
|
761
|
+
if (item.tooltip)
|
|
762
|
+
el.title = item.tooltip;
|
|
763
|
+
if (!item.disabled) {
|
|
764
|
+
el.addEventListener("click", () => {
|
|
765
|
+
closeContextMenu();
|
|
766
|
+
item.action();
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
sub.appendChild(el);
|
|
770
|
+
}
|
|
771
|
+
document.body.appendChild(sub);
|
|
772
|
+
const anchor = parentRow.getBoundingClientRect();
|
|
773
|
+
const vw = window.visualViewport?.width ?? window.innerWidth;
|
|
774
|
+
const vh = window.visualViewport?.height ?? window.innerHeight;
|
|
775
|
+
const rect = sub.getBoundingClientRect();
|
|
776
|
+
let left = anchor.right - 2;
|
|
777
|
+
if (left + rect.width > vw)
|
|
778
|
+
left = anchor.left - rect.width + 2;
|
|
779
|
+
let top = anchor.top;
|
|
780
|
+
if (top + rect.height > vh)
|
|
781
|
+
top = vh - rect.height - 4;
|
|
782
|
+
sub.style.left = `${Math.max(4, left)}px`;
|
|
783
|
+
sub.style.top = `${Math.max(4, top)}px`;
|
|
784
|
+
activeSubmenu = sub;
|
|
785
|
+
}
|
|
740
786
|
function showContextMenu(x, y, items) {
|
|
741
787
|
closeContextMenu();
|
|
742
788
|
const menu = document.createElement("div");
|
|
@@ -755,6 +801,24 @@ function showContextMenu(x, y, items) {
|
|
|
755
801
|
el.textContent = item.label;
|
|
756
802
|
if (item.tooltip)
|
|
757
803
|
el.title = item.tooltip;
|
|
804
|
+
if (item.submenu && item.submenu.length > 0 && !item.disabled) {
|
|
805
|
+
el.style.display = "flex";
|
|
806
|
+
el.style.justifyContent = "space-between";
|
|
807
|
+
el.style.gap = "12px";
|
|
808
|
+
const caret = document.createElement("span");
|
|
809
|
+
caret.textContent = "\u25B8";
|
|
810
|
+
caret.style.opacity = "0.6";
|
|
811
|
+
el.appendChild(caret);
|
|
812
|
+
const open = () => openSubmenu(el, item.submenu);
|
|
813
|
+
el.addEventListener("mouseenter", open);
|
|
814
|
+
el.addEventListener("click", (e) => {
|
|
815
|
+
e.stopPropagation();
|
|
816
|
+
open();
|
|
817
|
+
});
|
|
818
|
+
menu.appendChild(el);
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
el.addEventListener("mouseenter", closeSubmenu);
|
|
758
822
|
if (!item.disabled) {
|
|
759
823
|
el.addEventListener("click", () => {
|
|
760
824
|
closeContextMenu();
|
|
@@ -786,6 +850,8 @@ function showContextMenu(x, y, items) {
|
|
|
786
850
|
activeMenu = menu;
|
|
787
851
|
requestAnimationFrame(() => {
|
|
788
852
|
dismissListener = (e) => {
|
|
853
|
+
if (activeSubmenu?.contains(e.target))
|
|
854
|
+
return;
|
|
789
855
|
if (activeMenu && !activeMenu.contains(e.target)) {
|
|
790
856
|
closeContextMenu();
|
|
791
857
|
}
|
|
@@ -801,13 +867,14 @@ function showContextMenu(x, y, items) {
|
|
|
801
867
|
document.addEventListener("keydown", escapeListener, true);
|
|
802
868
|
});
|
|
803
869
|
}
|
|
804
|
-
var activeMenu, dismissListener, escapeListener;
|
|
870
|
+
var activeMenu, dismissListener, escapeListener, activeSubmenu;
|
|
805
871
|
var init_context_menu = __esm({
|
|
806
872
|
"client/components/context-menu.js"() {
|
|
807
873
|
"use strict";
|
|
808
874
|
activeMenu = null;
|
|
809
875
|
dismissListener = null;
|
|
810
876
|
escapeListener = null;
|
|
877
|
+
activeSubmenu = null;
|
|
811
878
|
document.addEventListener("scroll", closeContextMenu, true);
|
|
812
879
|
document.addEventListener("contextmenu", () => {
|
|
813
880
|
});
|
|
@@ -9117,6 +9184,17 @@ function showComposeOverlay(title = "Compose") {
|
|
|
9117
9184
|
document.body.appendChild(wrapper);
|
|
9118
9185
|
return frame;
|
|
9119
9186
|
}
|
|
9187
|
+
window.__msgerContextCommand = (id) => {
|
|
9188
|
+
const frames = [...document.querySelectorAll(".compose-overlay iframe")];
|
|
9189
|
+
const target = frames.sort((a, b) => {
|
|
9190
|
+
const z = (el) => Number(el.closest(".compose-overlay")?.style.zIndex || 0);
|
|
9191
|
+
return z(b) - z(a);
|
|
9192
|
+
})[0];
|
|
9193
|
+
try {
|
|
9194
|
+
target?.contentWindow?.__msgerContextCommand?.(id);
|
|
9195
|
+
} catch {
|
|
9196
|
+
}
|
|
9197
|
+
};
|
|
9120
9198
|
function installDragShield(cursor) {
|
|
9121
9199
|
const shield = document.createElement("div");
|
|
9122
9200
|
shield.style.cssText = `position:fixed;inset:0;z-index:9999;background:transparent;cursor:${cursor};user-select:none;`;
|