@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.
Files changed (33) hide show
  1. package/client/app.bundle.js +129 -1
  2. package/client/app.bundle.js.map +3 -3
  3. package/client/app.js +155 -0
  4. package/client/app.js.map +1 -1
  5. package/client/app.ts +139 -0
  6. package/client/components/context-menu.js +3 -1
  7. package/client/components/context-menu.js.map +1 -1
  8. package/client/components/context-menu.ts +5 -1
  9. package/client/compose/compose.bundle.js +7 -1
  10. package/client/compose/compose.bundle.js.map +2 -2
  11. package/client/lib/api-client.js +6 -0
  12. package/client/lib/api-client.js.map +1 -1
  13. package/client/lib/api-client.ts +7 -0
  14. package/package.json +1 -1
  15. package/packages/mailx-imap/index.d.ts.map +1 -1
  16. package/packages/mailx-imap/index.js +24 -0
  17. package/packages/mailx-imap/index.js.map +1 -1
  18. package/packages/mailx-imap/index.ts +25 -0
  19. package/packages/mailx-imap/package-lock.json +2 -2
  20. package/packages/mailx-imap/package.json +1 -1
  21. package/packages/mailx-service/index.d.ts +7 -0
  22. package/packages/mailx-service/index.d.ts.map +1 -1
  23. package/packages/mailx-service/index.js +15 -0
  24. package/packages/mailx-service/index.js.map +1 -1
  25. package/packages/mailx-service/index.ts +15 -0
  26. package/packages/mailx-service/jsonrpc.js +3 -0
  27. package/packages/mailx-service/jsonrpc.js.map +1 -1
  28. package/packages/mailx-service/jsonrpc.ts +3 -0
  29. package/packages/mailx-service/sync-queue.d.ts +5 -0
  30. package/packages/mailx-service/sync-queue.d.ts.map +1 -1
  31. package/packages/mailx-service/sync-queue.js +8 -0
  32. package/packages/mailx-service/sync-queue.js.map +1 -1
  33. package/packages/mailx-service/sync-queue.ts +9 -0
@@ -26,6 +26,7 @@ __export(api_client_exports, {
26
26
  connectEvents: () => connectEvents,
27
27
  connectWebSocket: () => connectWebSocket,
28
28
  consumePendingMailto: () => consumePendingMailto,
29
+ copyMessages: () => copyMessages,
29
30
  createCalendarEvent: () => createCalendarEvent,
30
31
  createFolder: () => createFolder,
31
32
  createTask: () => createTask,
@@ -345,6 +346,9 @@ function moveMessages(accountId, uids, targetFolderId, targetAccountId) {
345
346
  function markAsSpamMessages(accountId, uids) {
346
347
  return ipc().markAsSpamMessages?.(accountId, uids);
347
348
  }
349
+ function copyMessages(accountId, uids, folderIds, targetFolderId) {
350
+ return ipc().copyMessages?.(accountId, uids, folderIds, targetFolderId);
351
+ }
348
352
  function undeleteMessage(accountId, uid, folderId) {
349
353
  return ipc().undeleteMessage?.(accountId, uid, folderId);
350
354
  }
@@ -652,7 +656,9 @@ function showContextMenu(x, y, items) {
652
656
  continue;
653
657
  }
654
658
  const el = document.createElement("div");
655
- el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "");
659
+ el.className = "ctx-item" + (item.disabled ? " ctx-disabled" : "") + (item.emphasized ? " ctx-emphasized" : "");
660
+ if (item.emphasized)
661
+ el.style.fontWeight = "600";
656
662
  el.textContent = item.label;
657
663
  if (item.tooltip)
658
664
  el.title = item.tooltip;
@@ -8106,6 +8112,128 @@ async function performUndo() {
8106
8112
  document.addEventListener("mailx-moved", (e) => {
8107
8113
  pushUndo({ kind: "move", at: Date.now(), payload: e.detail });
8108
8114
  });
8115
+ (() => {
8116
+ const SLOP = 6;
8117
+ let cand = null;
8118
+ let active = false;
8119
+ let ghost = null;
8120
+ let suppressContext = false;
8121
+ const style = document.createElement("style");
8122
+ style.textContent = "body.rmf-rdrag, body.rmf-rdrag * { cursor: grabbing !important; }.rmf-rdrag-ghost { position: fixed; z-index: 100000; pointer-events: none; background: var(--color-accent, #1a6dd4); color: #fff; padding: 2px 9px; border-radius: 4px; font: 12px system-ui; box-shadow: 0 2px 8px rgba(0,0,0,.3); }.ft-folder.rmf-rdrag-over { outline: 2px solid var(--color-accent, #1a6dd4); outline-offset: -2px; border-radius: 4px; }";
8123
+ document.head.appendChild(style);
8124
+ const folderAt = (x, y) => document.elementFromPoint(x, y)?.closest?.(".ft-folder") || null;
8125
+ const clearOver = () => document.querySelectorAll(".ft-folder.rmf-rdrag-over").forEach((el) => el.classList.remove("rmf-rdrag-over"));
8126
+ const cleanup = () => {
8127
+ active = false;
8128
+ cand = null;
8129
+ document.body.classList.remove("rmf-rdrag");
8130
+ ghost?.remove();
8131
+ ghost = null;
8132
+ clearOver();
8133
+ };
8134
+ document.addEventListener("mousedown", (e) => {
8135
+ if (e.button !== 2) return;
8136
+ const row = e.target?.closest?.(".ml-row");
8137
+ if (!row) return;
8138
+ const pressed = {
8139
+ accountId: row.dataset.accountId || "",
8140
+ uid: Number(row.dataset.uid),
8141
+ folderId: Number(row.dataset.folderId)
8142
+ };
8143
+ if (!pressed.uid) return;
8144
+ let msgs = getSelectedMessages();
8145
+ if (!msgs.some((m) => m.accountId === pressed.accountId && m.uid === pressed.uid)) msgs = [pressed];
8146
+ cand = { msgs, x: e.clientX, y: e.clientY };
8147
+ active = false;
8148
+ }, true);
8149
+ document.addEventListener("mousemove", (e) => {
8150
+ if (!cand) return;
8151
+ if (!active) {
8152
+ if (Math.abs(e.clientX - cand.x) < SLOP && Math.abs(e.clientY - cand.y) < SLOP) return;
8153
+ active = true;
8154
+ document.body.classList.add("rmf-rdrag");
8155
+ ghost = document.createElement("div");
8156
+ ghost.className = "rmf-rdrag-ghost";
8157
+ ghost.textContent = cand.msgs.length === 1 ? "1 message" : `${cand.msgs.length} messages`;
8158
+ document.body.appendChild(ghost);
8159
+ }
8160
+ if (ghost) {
8161
+ ghost.style.left = `${e.clientX + 14}px`;
8162
+ ghost.style.top = `${e.clientY + 8}px`;
8163
+ }
8164
+ clearOver();
8165
+ folderAt(e.clientX, e.clientY)?.classList.add("rmf-rdrag-over");
8166
+ }, true);
8167
+ document.addEventListener("mouseup", (e) => {
8168
+ if (!cand) return;
8169
+ const wasActive = active;
8170
+ const msgs = cand.msgs;
8171
+ const folder = wasActive ? folderAt(e.clientX, e.clientY) : null;
8172
+ const mx = e.clientX, my = e.clientY;
8173
+ cleanup();
8174
+ if (!wasActive) return;
8175
+ suppressContext = true;
8176
+ if (!folder) return;
8177
+ e.preventDefault();
8178
+ e.stopPropagation();
8179
+ const targetAccount = folder.dataset.accountId || "";
8180
+ const targetFolderId = Number(folder.dataset.folderId);
8181
+ const targetName = folder.querySelector(".ft-folder-name")?.textContent?.trim() || "folder";
8182
+ void showRightDragMenu(mx, my, msgs, targetAccount, targetFolderId, targetName);
8183
+ }, true);
8184
+ document.addEventListener("contextmenu", (e) => {
8185
+ if (suppressContext) {
8186
+ e.preventDefault();
8187
+ e.stopPropagation();
8188
+ suppressContext = false;
8189
+ }
8190
+ }, true);
8191
+ async function showRightDragMenu(x, y, msgs, targetAccount, targetFolderId, targetName) {
8192
+ const { showContextMenu: showContextMenu2 } = await Promise.resolve().then(() => (init_context_menu(), context_menu_exports));
8193
+ const n = msgs.length;
8194
+ const label = n === 1 ? "message" : `${n} messages`;
8195
+ showContextMenu2(x, y, [
8196
+ { label: `Move ${label} here`, emphasized: true, action: () => void runRightDragOp(msgs, targetAccount, targetFolderId, targetName, "move") },
8197
+ { label: `Copy ${label} here`, action: () => void runRightDragOp(msgs, targetAccount, targetFolderId, targetName, "copy") }
8198
+ ]);
8199
+ }
8200
+ async function runRightDragOp(msgs, targetAccount, targetFolderId, targetName, op) {
8201
+ const status = document.getElementById("status-sync");
8202
+ const api = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
8203
+ const byAccount = /* @__PURE__ */ new Map();
8204
+ for (const m of msgs) {
8205
+ const g = byAccount.get(m.accountId) || { uids: [], folderIds: [] };
8206
+ g.uids.push(m.uid);
8207
+ g.folderIds.push(m.folderId);
8208
+ byAccount.set(m.accountId, g);
8209
+ }
8210
+ if (op === "move") {
8211
+ removeMessagesAndReconcile(msgs);
8212
+ document.dispatchEvent(new CustomEvent("mailx-moved", {
8213
+ detail: { messages: msgs.map((m) => ({ accountId: m.accountId, uid: m.uid, sourceFolderId: m.folderId })) }
8214
+ }));
8215
+ for (const [src, g] of byAccount) {
8216
+ const targetAcct = src === targetAccount ? void 0 : targetAccount;
8217
+ api.moveMessages(src, g.uids, targetFolderId, targetAcct)?.catch?.((err) => {
8218
+ if (status) status.textContent = `Move failed: ${err?.message || err}`;
8219
+ });
8220
+ }
8221
+ if (status) status.textContent = `Moved ${msgs.length} to ${targetName} \u2014 Ctrl+Z to undo`;
8222
+ } else {
8223
+ let skippedXacct = false;
8224
+ for (const [src, g] of byAccount) {
8225
+ if (src !== targetAccount) {
8226
+ skippedXacct = true;
8227
+ continue;
8228
+ }
8229
+ api.copyMessages(src, g.uids, g.folderIds, targetFolderId)?.catch?.((err) => {
8230
+ if (status) status.textContent = `Copy failed: ${err?.message || err}`;
8231
+ });
8232
+ }
8233
+ if (status) status.textContent = skippedXacct ? `Copy across accounts isn't supported yet` : `Copying ${msgs.length} to ${targetName}\u2026`;
8234
+ }
8235
+ }
8236
+ })();
8109
8237
  document.getElementById("btn-delete")?.addEventListener("click", deleteSelection);
8110
8238
  document.getElementById("btn-tb-delete")?.addEventListener("click", deleteSelection);
8111
8239
  document.getElementById("btn-tb-spam")?.addEventListener("click", spamSelectedMessages);