@bobfrankston/rmfmail 1.1.248 → 1.1.249
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 +129 -1
- package/client/app.bundle.js.map +3 -3
- package/client/app.js +155 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +139 -0
- package/client/components/context-menu.js +3 -1
- package/client/components/context-menu.js.map +1 -1
- package/client/components/context-menu.ts +5 -1
- package/client/compose/compose.bundle.js +7 -1
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/lib/api-client.js +6 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +7 -0
- package/package.json +1 -1
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +24 -0
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +25 -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 +7 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +15 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +15 -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/sync-queue.d.ts +5 -0
- package/packages/mailx-service/sync-queue.d.ts.map +1 -1
- package/packages/mailx-service/sync-queue.js +8 -0
- package/packages/mailx-service/sync-queue.js.map +1 -1
- package/packages/mailx-service/sync-queue.ts +9 -0
package/client/app.ts
CHANGED
|
@@ -1596,6 +1596,145 @@ document.addEventListener("mailx-moved", (e: any) => {
|
|
|
1596
1596
|
pushUndo({ kind: "move", at: Date.now(), payload: e.detail as MovedBatch });
|
|
1597
1597
|
});
|
|
1598
1598
|
|
|
1599
|
+
// ── Right-button drag → Move / Copy menu ───────────────────────────────
|
|
1600
|
+
// Browser drag-and-drop is left-button only, so a RIGHT-button drag is a
|
|
1601
|
+
// custom mouse-tracked gesture: right-press a message row, drag onto a folder
|
|
1602
|
+
// in the tree, release → a menu offers Move (default, bold) or Copy. A plain
|
|
1603
|
+
// left drag still moves directly; a plain right-CLICK (no movement) still opens
|
|
1604
|
+
// the normal message menu — only a right-press-AND-drag triggers this.
|
|
1605
|
+
(() => {
|
|
1606
|
+
type RDMsg = { accountId: string; uid: number; folderId: number };
|
|
1607
|
+
const SLOP = 6;
|
|
1608
|
+
let cand: { msgs: RDMsg[]; x: number; y: number } | null = null;
|
|
1609
|
+
let active = false;
|
|
1610
|
+
let ghost: HTMLElement | null = null;
|
|
1611
|
+
let suppressContext = false;
|
|
1612
|
+
|
|
1613
|
+
// Cursor + ghost + drop-highlight styles (self-contained).
|
|
1614
|
+
const style = document.createElement("style");
|
|
1615
|
+
style.textContent =
|
|
1616
|
+
"body.rmf-rdrag, body.rmf-rdrag * { cursor: grabbing !important; }" +
|
|
1617
|
+
".rmf-rdrag-ghost { position: fixed; z-index: 100000; pointer-events: none;" +
|
|
1618
|
+
" background: var(--color-accent, #1a6dd4); color: #fff; padding: 2px 9px;" +
|
|
1619
|
+
" border-radius: 4px; font: 12px system-ui; box-shadow: 0 2px 8px rgba(0,0,0,.3); }" +
|
|
1620
|
+
".ft-folder.rmf-rdrag-over { outline: 2px solid var(--color-accent, #1a6dd4); outline-offset: -2px; border-radius: 4px; }";
|
|
1621
|
+
document.head.appendChild(style);
|
|
1622
|
+
|
|
1623
|
+
const folderAt = (x: number, y: number): HTMLElement | null =>
|
|
1624
|
+
((document.elementFromPoint(x, y) as HTMLElement | null)?.closest?.(".ft-folder") as HTMLElement | null) || null;
|
|
1625
|
+
const clearOver = (): void =>
|
|
1626
|
+
document.querySelectorAll(".ft-folder.rmf-rdrag-over").forEach(el => el.classList.remove("rmf-rdrag-over"));
|
|
1627
|
+
const cleanup = (): void => {
|
|
1628
|
+
active = false; cand = null;
|
|
1629
|
+
document.body.classList.remove("rmf-rdrag");
|
|
1630
|
+
ghost?.remove(); ghost = null;
|
|
1631
|
+
clearOver();
|
|
1632
|
+
};
|
|
1633
|
+
|
|
1634
|
+
document.addEventListener("mousedown", (e) => {
|
|
1635
|
+
if (e.button !== 2) return;
|
|
1636
|
+
const row = (e.target as HTMLElement)?.closest?.(".ml-row") as HTMLElement | null;
|
|
1637
|
+
if (!row) return;
|
|
1638
|
+
const pressed: RDMsg = {
|
|
1639
|
+
accountId: row.dataset.accountId || "",
|
|
1640
|
+
uid: Number(row.dataset.uid),
|
|
1641
|
+
folderId: Number(row.dataset.folderId),
|
|
1642
|
+
};
|
|
1643
|
+
if (!pressed.uid) return;
|
|
1644
|
+
// Drag the current multi-selection if the pressed row is in it;
|
|
1645
|
+
// otherwise just the pressed row.
|
|
1646
|
+
let msgs = getSelectedMessages();
|
|
1647
|
+
if (!msgs.some(m => m.accountId === pressed.accountId && m.uid === pressed.uid)) msgs = [pressed];
|
|
1648
|
+
cand = { msgs, x: e.clientX, y: e.clientY };
|
|
1649
|
+
active = false;
|
|
1650
|
+
}, true);
|
|
1651
|
+
|
|
1652
|
+
document.addEventListener("mousemove", (e) => {
|
|
1653
|
+
if (!cand) return;
|
|
1654
|
+
if (!active) {
|
|
1655
|
+
if (Math.abs(e.clientX - cand.x) < SLOP && Math.abs(e.clientY - cand.y) < SLOP) return;
|
|
1656
|
+
active = true;
|
|
1657
|
+
document.body.classList.add("rmf-rdrag");
|
|
1658
|
+
ghost = document.createElement("div");
|
|
1659
|
+
ghost.className = "rmf-rdrag-ghost";
|
|
1660
|
+
ghost.textContent = cand.msgs.length === 1 ? "1 message" : `${cand.msgs.length} messages`;
|
|
1661
|
+
document.body.appendChild(ghost);
|
|
1662
|
+
}
|
|
1663
|
+
if (ghost) { ghost.style.left = `${e.clientX + 14}px`; ghost.style.top = `${e.clientY + 8}px`; }
|
|
1664
|
+
clearOver();
|
|
1665
|
+
folderAt(e.clientX, e.clientY)?.classList.add("rmf-rdrag-over");
|
|
1666
|
+
}, true);
|
|
1667
|
+
|
|
1668
|
+
document.addEventListener("mouseup", (e) => {
|
|
1669
|
+
if (!cand) return;
|
|
1670
|
+
const wasActive = active;
|
|
1671
|
+
const msgs = cand.msgs;
|
|
1672
|
+
const folder = wasActive ? folderAt(e.clientX, e.clientY) : null;
|
|
1673
|
+
const mx = e.clientX, my = e.clientY;
|
|
1674
|
+
cleanup();
|
|
1675
|
+
if (!wasActive) return; // a right-click, not a drag
|
|
1676
|
+
suppressContext = true; // eat the contextmenu that fires next
|
|
1677
|
+
if (!folder) return; // released off any folder
|
|
1678
|
+
e.preventDefault(); e.stopPropagation();
|
|
1679
|
+
const targetAccount = folder.dataset.accountId || "";
|
|
1680
|
+
const targetFolderId = Number(folder.dataset.folderId);
|
|
1681
|
+
const targetName = folder.querySelector(".ft-folder-name")?.textContent?.trim() || "folder";
|
|
1682
|
+
void showRightDragMenu(mx, my, msgs, targetAccount, targetFolderId, targetName);
|
|
1683
|
+
}, true);
|
|
1684
|
+
|
|
1685
|
+
// Suppress the folder/message context menu that would otherwise pop on the
|
|
1686
|
+
// right-button release after a drag.
|
|
1687
|
+
document.addEventListener("contextmenu", (e) => {
|
|
1688
|
+
if (suppressContext) { e.preventDefault(); e.stopPropagation(); suppressContext = false; }
|
|
1689
|
+
}, true);
|
|
1690
|
+
|
|
1691
|
+
async function showRightDragMenu(x: number, y: number, msgs: RDMsg[], targetAccount: string, targetFolderId: number, targetName: string): Promise<void> {
|
|
1692
|
+
const { showContextMenu } = await import("./components/context-menu.js");
|
|
1693
|
+
const n = msgs.length;
|
|
1694
|
+
const label = n === 1 ? "message" : `${n} messages`;
|
|
1695
|
+
showContextMenu(x, y, [
|
|
1696
|
+
{ label: `Move ${label} here`, emphasized: true, action: () => void runRightDragOp(msgs, targetAccount, targetFolderId, targetName, "move") },
|
|
1697
|
+
{ label: `Copy ${label} here`, action: () => void runRightDragOp(msgs, targetAccount, targetFolderId, targetName, "copy") },
|
|
1698
|
+
]);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
async function runRightDragOp(msgs: RDMsg[], targetAccount: string, targetFolderId: number, targetName: string, op: "move" | "copy"): Promise<void> {
|
|
1702
|
+
const status = document.getElementById("status-sync");
|
|
1703
|
+
const api = await import("./lib/api-client.js");
|
|
1704
|
+
const byAccount = new Map<string, { uids: number[]; folderIds: number[] }>();
|
|
1705
|
+
for (const m of msgs) {
|
|
1706
|
+
const g = byAccount.get(m.accountId) || { uids: [], folderIds: [] };
|
|
1707
|
+
g.uids.push(m.uid); g.folderIds.push(m.folderId);
|
|
1708
|
+
byAccount.set(m.accountId, g);
|
|
1709
|
+
}
|
|
1710
|
+
if (op === "move") {
|
|
1711
|
+
// Optimistic remove + undo, mirroring the left-drag drop handler.
|
|
1712
|
+
removeMessagesAndReconcile(msgs);
|
|
1713
|
+
document.dispatchEvent(new CustomEvent("mailx-moved", {
|
|
1714
|
+
detail: { messages: msgs.map(m => ({ accountId: m.accountId, uid: m.uid, sourceFolderId: m.folderId })) },
|
|
1715
|
+
}));
|
|
1716
|
+
for (const [src, g] of byAccount) {
|
|
1717
|
+
const targetAcct = src === targetAccount ? undefined : targetAccount;
|
|
1718
|
+
api.moveMessages(src, g.uids, targetFolderId, targetAcct)?.catch?.((err: any) => {
|
|
1719
|
+
if (status) status.textContent = `Move failed: ${err?.message || err}`;
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
if (status) status.textContent = `Moved ${msgs.length} to ${targetName} — Ctrl+Z to undo`;
|
|
1723
|
+
} else {
|
|
1724
|
+
let skippedXacct = false;
|
|
1725
|
+
for (const [src, g] of byAccount) {
|
|
1726
|
+
if (src !== targetAccount) { skippedXacct = true; continue; } // copy is same-account for now
|
|
1727
|
+
api.copyMessages(src, g.uids, g.folderIds, targetFolderId)?.catch?.((err: any) => {
|
|
1728
|
+
if (status) status.textContent = `Copy failed: ${err?.message || err}`;
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
if (status) status.textContent = skippedXacct
|
|
1732
|
+
? `Copy across accounts isn't supported yet`
|
|
1733
|
+
: `Copying ${msgs.length} to ${targetName}…`;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
})();
|
|
1737
|
+
|
|
1599
1738
|
document.getElementById("btn-delete")?.addEventListener("click", deleteSelection);
|
|
1600
1739
|
// Same handlers also bound to the top-toolbar icons so delete/spam work
|
|
1601
1740
|
// regardless of whether a message is open in the viewer. Useful for quick
|
|
@@ -33,7 +33,9 @@ export function showContextMenu(x, y, items) {
|
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
const el = document.createElement("div");
|
|
36
|
-
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
|
|
36
|
+
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "") + (item.emphasized ? " ctx-emphasized" : "");
|
|
37
|
+
if (item.emphasized)
|
|
38
|
+
el.style.fontWeight = "600";
|
|
37
39
|
el.textContent = item.label;
|
|
38
40
|
if (item.tooltip)
|
|
39
41
|
el.title = item.tooltip;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-menu.js","sourceRoot":"","sources":["context-menu.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,IAAI,UAAU,GAAuB,IAAI,CAAC;AAC1C,IAAI,eAAe,GAAgC,IAAI,CAAC;AACxD,IAAI,cAAc,GAAwC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"context-menu.js","sourceRoot":"","sources":["context-menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,9 @@ export interface MenuItem {
|
|
|
12
12
|
action: () => void;
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
separator?: boolean;
|
|
15
|
+
/** Render bold, as the menu's default/primary action (e.g. "Move here"
|
|
16
|
+
* in the right-drag menu, vs the secondary "Copy here"). */
|
|
17
|
+
emphasized?: boolean;
|
|
15
18
|
/** Native browser tooltip shown on hover (title attribute). Use it
|
|
16
19
|
* to explain non-obvious side effects of an action — e.g., "skips
|
|
17
20
|
* Trash, no undo" so the user can tell two near-identical entries
|
|
@@ -50,7 +53,8 @@ export function showContextMenu(x: number, y: number, items: MenuItem[]): void {
|
|
|
50
53
|
continue;
|
|
51
54
|
}
|
|
52
55
|
const el = document.createElement("div");
|
|
53
|
-
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
|
|
56
|
+
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "") + (item.emphasized ? " ctx-emphasized" : "");
|
|
57
|
+
if (item.emphasized) el.style.fontWeight = "600";
|
|
54
58
|
el.textContent = item.label;
|
|
55
59
|
if (item.tooltip) el.title = item.tooltip;
|
|
56
60
|
if (!item.disabled) {
|
|
@@ -1019,6 +1019,7 @@ __export(api_client_exports, {
|
|
|
1019
1019
|
connectEvents: () => connectEvents,
|
|
1020
1020
|
connectWebSocket: () => connectWebSocket,
|
|
1021
1021
|
consumePendingMailto: () => consumePendingMailto,
|
|
1022
|
+
copyMessages: () => copyMessages,
|
|
1022
1023
|
createCalendarEvent: () => createCalendarEvent,
|
|
1023
1024
|
createFolder: () => createFolder,
|
|
1024
1025
|
createTask: () => createTask,
|
|
@@ -1338,6 +1339,9 @@ function moveMessages(accountId, uids, targetFolderId, targetAccountId) {
|
|
|
1338
1339
|
function markAsSpamMessages(accountId, uids) {
|
|
1339
1340
|
return ipc().markAsSpamMessages?.(accountId, uids);
|
|
1340
1341
|
}
|
|
1342
|
+
function copyMessages(accountId, uids, folderIds, targetFolderId) {
|
|
1343
|
+
return ipc().copyMessages?.(accountId, uids, folderIds, targetFolderId);
|
|
1344
|
+
}
|
|
1341
1345
|
function undeleteMessage(accountId, uid, folderId) {
|
|
1342
1346
|
return ipc().undeleteMessage?.(accountId, uid, folderId);
|
|
1343
1347
|
}
|
|
@@ -3461,7 +3465,9 @@ function showContextMenu(x, y, items) {
|
|
|
3461
3465
|
continue;
|
|
3462
3466
|
}
|
|
3463
3467
|
const el = document.createElement("div");
|
|
3464
|
-
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
|
|
3468
|
+
el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "") + (item.emphasized ? " ctx-emphasized" : "");
|
|
3469
|
+
if (item.emphasized)
|
|
3470
|
+
el.style.fontWeight = "600";
|
|
3465
3471
|
el.textContent = item.label;
|
|
3466
3472
|
if (item.tooltip)
|
|
3467
3473
|
el.title = item.tooltip;
|