@bobfrankston/rmfmail 1.2.115 → 1.2.117

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.
@@ -1024,10 +1024,12 @@ __export(api_client_exports, {
1024
1024
  autocomplete: () => autocomplete,
1025
1025
  cancelQueuedOutgoing: () => cancelQueuedOutgoing,
1026
1026
  cancelServerSearch: () => cancelServerSearch,
1027
+ closeComposePopout: () => closeComposePopout,
1027
1028
  closeWordEdit: () => closeWordEdit,
1028
1029
  connectEvents: () => connectEvents,
1029
1030
  connectWebSocket: () => connectWebSocket,
1030
1031
  consumePendingMailto: () => consumePendingMailto,
1032
+ consumePopoutComposeInit: () => consumePopoutComposeInit,
1031
1033
  copyMessages: () => copyMessages,
1032
1034
  createCalendarEvent: () => createCalendarEvent,
1033
1035
  createFolder: () => createFolder,
@@ -1082,6 +1084,7 @@ __export(api_client_exports, {
1082
1084
  openInTextEditor: () => openInTextEditor,
1083
1085
  openInWord: () => openInWord,
1084
1086
  openLocalPath: () => openLocalPath,
1087
+ popoutCompose: () => popoutCompose,
1085
1088
  popoutWindow: () => popoutWindow,
1086
1089
  readConfigHelp: () => readConfigHelp,
1087
1090
  readJsoncFile: () => readJsoncFile,
@@ -1625,6 +1628,22 @@ async function popoutWindow(accountId, uid, folderId, subject) {
1625
1628
  return { ok: false, reason: "no popoutWindow bridge" };
1626
1629
  return fn(accountId, uid, folderId, subject);
1627
1630
  }
1631
+ async function popoutCompose(init) {
1632
+ const fn = ipc().popoutCompose;
1633
+ if (!fn)
1634
+ return { ok: false, reason: "no popoutCompose bridge" };
1635
+ return fn(init);
1636
+ }
1637
+ async function consumePopoutComposeInit(id) {
1638
+ const fn = ipc().consumePopoutComposeInit;
1639
+ if (!fn)
1640
+ return { init: null };
1641
+ return fn(id);
1642
+ }
1643
+ function closeComposePopout(id) {
1644
+ const fn = ipc().closeComposePopout;
1645
+ return fn ? fn(id) : Promise.resolve({ ok: false });
1646
+ }
1628
1647
  async function getDeviceAccounts() {
1629
1648
  return ipc().getDeviceAccounts?.() ?? [];
1630
1649
  }
@@ -3725,8 +3744,13 @@ function _ctick(label) {
3725
3744
  }
3726
3745
  }
3727
3746
  _ctick("module body executing");
3747
+ var popoutInitId = new URLSearchParams(location.search).get("pi") || "";
3728
3748
  function closeCompose() {
3729
3749
  logClientEvent("compose-close");
3750
+ if (popoutInitId) {
3751
+ void closeComposePopout(popoutInitId).catch(() => {
3752
+ });
3753
+ }
3730
3754
  try {
3731
3755
  parent.postMessage({ type: "mailx-compose-close" }, "*");
3732
3756
  } catch {
@@ -4124,6 +4148,17 @@ function getFromAccountId() {
4124
4148
  function getFromAddress() {
4125
4149
  return fromInput.value.trim();
4126
4150
  }
4151
+ function smartTab(current) {
4152
+ const fields = [toInput, ccInput, bccInput, subjectInput];
4153
+ const currentIdx = fields.indexOf(current);
4154
+ for (let i = currentIdx + 1; i < fields.length; i++) {
4155
+ if (!fields[i].value.trim() && fields[i].offsetParent !== null) {
4156
+ fields[i].focus();
4157
+ return;
4158
+ }
4159
+ }
4160
+ editor.focus();
4161
+ }
4127
4162
  function showAutocompleteContextMenu(e, row) {
4128
4163
  showContextMenu(e.clientX, e.clientY, [
4129
4164
  {
@@ -4370,6 +4405,14 @@ function setupAutocomplete(input) {
4370
4405
  setupAutocomplete(toInput);
4371
4406
  setupAutocomplete(ccInput);
4372
4407
  setupAutocomplete(bccInput);
4408
+ for (const field of [toInput, ccInput, bccInput, subjectInput]) {
4409
+ field.addEventListener("keydown", (e) => {
4410
+ const ke = e;
4411
+ if (ke.key !== "Tab" || ke.shiftKey || ke.ctrlKey || ke.altKey || ke.defaultPrevented) return;
4412
+ ke.preventDefault();
4413
+ smartTab(field);
4414
+ });
4415
+ }
4373
4416
  function splitRecipients(s) {
4374
4417
  const raw = [];
4375
4418
  let cur = "", inQuote = false;
@@ -4478,17 +4521,26 @@ function expandGroups(raw) {
4478
4521
  }
4479
4522
  function applyInit(init) {
4480
4523
  populateFromOptions(init.accounts, init.accountId);
4481
- if (init.fromAddress) {
4524
+ if (init.fromRaw) {
4525
+ fromInput.value = init.fromRaw;
4526
+ } else if (init.fromAddress) {
4482
4527
  const account = init.accounts.find((a) => a.id === init.accountId);
4483
4528
  const displayName = account?.name || "";
4484
4529
  fromInput.value = displayName ? `${displayName} <${init.fromAddress}>` : init.fromAddress;
4485
4530
  }
4486
4531
  toInput.value = formatAddrs(init.to);
4487
4532
  ccInput.value = formatAddrs(init.cc);
4533
+ bccInput.value = formatAddrs(init.bcc || []);
4488
4534
  subjectInput.value = init.subject;
4489
4535
  autoGrowAddrInput(toInput);
4490
4536
  autoGrowAddrInput(ccInput);
4491
4537
  autoGrowAddrInput(bccInput);
4538
+ if (bccInput.value.trim()) {
4539
+ const bccRowEl = document.getElementById("compose-bcc-row");
4540
+ const bccBtn = document.getElementById("btn-toggle-bcc");
4541
+ if (bccRowEl) bccRowEl.hidden = false;
4542
+ if (bccBtn) bccBtn.classList.add("active");
4543
+ }
4492
4544
  if (ccInput.value.trim()) {
4493
4545
  const ccRowEl = document.getElementById("compose-cc-row");
4494
4546
  const ccBtn = document.getElementById("btn-toggle-cc");
@@ -4728,19 +4780,33 @@ function waitForParentInit(maxMs) {
4728
4780
  }
4729
4781
  (async () => {
4730
4782
  _ctick("init IIFE start");
4731
- let parentInit = pullInitFromParent();
4732
- if (!parentInit && !sessionStorage.getItem("composeInit") && !_postedInit) {
4733
- _ctick("waiting for parent init");
4734
- await waitForParentInit(1500);
4735
- _ctick(`parent init received (msgEvents=${_msgEventCount})`);
4736
- if (!_postedInit) parentInit = pullInitFromParent();
4783
+ let parentInit = null;
4784
+ if (popoutInitId) {
4785
+ try {
4786
+ parentInit = (await consumePopoutComposeInit(popoutInitId))?.init || null;
4787
+ } catch (e) {
4788
+ console.error("Failed to fetch popout compose init:", e);
4789
+ }
4790
+ _ctick(`popout init ${parentInit ? "received" : "MISSING"}`);
4791
+ try {
4792
+ document.title = parentInit?.subject ? `Compose: ${parentInit.subject}` : "Compose";
4793
+ } catch {
4794
+ }
4795
+ } else {
4796
+ parentInit = pullInitFromParent();
4797
+ if (!parentInit && !sessionStorage.getItem("composeInit") && !_postedInit) {
4798
+ _ctick("waiting for parent init");
4799
+ await waitForParentInit(1500);
4800
+ _ctick(`parent init received (msgEvents=${_msgEventCount})`);
4801
+ if (!_postedInit) parentInit = pullInitFromParent();
4802
+ }
4737
4803
  }
4738
4804
  const stored = sessionStorage.getItem("composeInit");
4739
4805
  const initRaw = parentInit || _postedInit || (stored ? JSON.parse(stored) : null);
4740
4806
  if (initRaw) {
4741
4807
  sessionStorage.removeItem("composeInit");
4742
4808
  const init = initRaw;
4743
- const src = parentInit ? "parent-stash" : _postedInit ? "postMessage" : "sessionStorage";
4809
+ const src = parentInit ? popoutInitId ? "popout" : "parent-stash" : _postedInit ? "postMessage" : "sessionStorage";
4744
4810
  _ctick(`init parsed (mode=${init.mode}, bodyHtml=${init.bodyHtml?.length || 0} bytes, src=${src})`);
4745
4811
  if (init.accounts && init.accounts.length > 0) {
4746
4812
  applyInit(init);
@@ -5025,6 +5091,50 @@ document.getElementById("btn-discard")?.addEventListener("click", async () => {
5025
5091
  }
5026
5092
  closeCompose();
5027
5093
  });
5094
+ var composePopoutBtn = document.getElementById("btn-compose-popout");
5095
+ if (composePopoutBtn && popoutInitId) composePopoutBtn.style.display = "none";
5096
+ composePopoutBtn?.addEventListener("click", async () => {
5097
+ if (!draftId) draftId = `mailx-draft-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
5098
+ const init = {
5099
+ // "draft" mode so applyInit does NOT re-append the signature — the
5100
+ // body already carries whatever the user has (sig included).
5101
+ mode: "draft",
5102
+ accountId: getFromAccountId(),
5103
+ to: parseAddrs(toInput.value),
5104
+ cc: parseAddrs(ccInput.value),
5105
+ bcc: parseAddrs(bccInput.value),
5106
+ subject: subjectInput.value,
5107
+ bodyHtml: editor.getHtml(),
5108
+ inReplyTo: replyInReplyTo,
5109
+ references: replyReferences,
5110
+ accounts: knownAccounts,
5111
+ fromRaw: getFromAddress(),
5112
+ attachments: attachments.map((a) => ({ filename: a.filename, mimeType: a.mimeType, dataBase64: a.dataBase64 })),
5113
+ draftUid: draftUid ?? void 0,
5114
+ draftId: draftId ?? void 0
5115
+ };
5116
+ composePopoutBtn.disabled = true;
5117
+ try {
5118
+ const r = await popoutCompose(init);
5119
+ if (r?.ok) {
5120
+ if (draftDebounceTimer) {
5121
+ clearTimeout(draftDebounceTimer);
5122
+ draftDebounceTimer = null;
5123
+ }
5124
+ if (draftTimer) {
5125
+ clearInterval(draftTimer);
5126
+ draftTimer = null;
5127
+ }
5128
+ closeCompose();
5129
+ } else {
5130
+ showDraftStatus(`Popout failed: ${r?.reason || "unknown"}`, true);
5131
+ composePopoutBtn.disabled = false;
5132
+ }
5133
+ } catch (e) {
5134
+ showDraftStatus(`Popout failed: ${e?.message || e}`, true);
5135
+ composePopoutBtn.disabled = false;
5136
+ }
5137
+ });
5028
5138
  var ccRow = document.getElementById("compose-cc-row");
5029
5139
  var bccRow = document.getElementById("compose-bcc-row");
5030
5140
  var toggleCcBtn = document.getElementById("btn-toggle-cc");