@bobfrankston/rmfmail 1.1.43 → 1.1.45

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.
@@ -2151,9 +2151,29 @@ function spawnDesktopPopout(msg, accountId) {
2151
2151
  wrapper.style.top = `${60 + existing * 28}px`;
2152
2152
  wrapper.style.right = `${20 + existing * 28}px`;
2153
2153
  }
2154
- void accountId;
2154
+ const toolbar = document.createElement("div");
2155
+ toolbar.style.cssText = "display:flex;gap:6px;padding:6px 12px;border-bottom:1px solid var(--color-border, #ddd);flex-shrink:0;";
2156
+ const mkPopoutBtn = (label, title, onClick) => {
2157
+ const b = document.createElement("button");
2158
+ b.textContent = label;
2159
+ b.title = title;
2160
+ b.style.cssText = "padding:4px 10px;font-size:13px;cursor:pointer;border:1px solid var(--color-border, #ccc);border-radius:4px;background:var(--color-bg, #fff);color:var(--color-text, #000);";
2161
+ b.addEventListener("click", onClick);
2162
+ return b;
2163
+ };
2164
+ const firePopoutAction = (action) => {
2165
+ document.dispatchEvent(new CustomEvent("mailx-popout-action", { detail: { action, msg, accountId } }));
2166
+ };
2167
+ toolbar.appendChild(mkPopoutBtn("Reply", "Reply", () => firePopoutAction("reply")));
2168
+ toolbar.appendChild(mkPopoutBtn("Reply All", "Reply to all", () => firePopoutAction("replyAll")));
2169
+ toolbar.appendChild(mkPopoutBtn("Forward", "Forward", () => firePopoutAction("forward")));
2170
+ toolbar.appendChild(mkPopoutBtn("Delete", "Delete this message", () => {
2171
+ firePopoutAction("delete");
2172
+ wrapper.remove();
2173
+ }));
2155
2174
  wrapper.appendChild(titleBar);
2156
2175
  wrapper.appendChild(headerInfo);
2176
+ wrapper.appendChild(toolbar);
2157
2177
  wrapper.appendChild(bodyContainer);
2158
2178
  document.body.appendChild(wrapper);
2159
2179
  }
@@ -5076,6 +5096,135 @@ var init_alarms = __esm({
5076
5096
  // client/components/folder-tree.js
5077
5097
  init_api_client();
5078
5098
  init_context_menu();
5099
+
5100
+ // client/components/tabs.js
5101
+ var STORAGE_KEY = "mailx-view-tabs";
5102
+ var tabs = [];
5103
+ var activeId = "";
5104
+ var stripEl = null;
5105
+ var applyView = () => {
5106
+ };
5107
+ var _nextId = 1;
5108
+ function newId() {
5109
+ return `t${_nextId++}`;
5110
+ }
5111
+ function persist() {
5112
+ try {
5113
+ sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ tabs, activeId }));
5114
+ } catch {
5115
+ }
5116
+ }
5117
+ function render() {
5118
+ if (!stripEl)
5119
+ return;
5120
+ stripEl.innerHTML = "";
5121
+ for (const tab of tabs) {
5122
+ const chip = document.createElement("div");
5123
+ chip.className = "view-tab" + (tab.id === activeId ? " active" : "");
5124
+ chip.dataset.tabId = tab.id;
5125
+ const label = document.createElement("span");
5126
+ label.className = "view-tab-label";
5127
+ label.textContent = tab.title || "(view)";
5128
+ chip.appendChild(label);
5129
+ if (tabs.length > 1) {
5130
+ const close = document.createElement("button");
5131
+ close.className = "view-tab-close";
5132
+ close.textContent = "\xD7";
5133
+ close.title = "Close tab";
5134
+ close.addEventListener("click", (e) => {
5135
+ e.stopPropagation();
5136
+ closeTab(tab.id);
5137
+ });
5138
+ chip.appendChild(close);
5139
+ }
5140
+ chip.addEventListener("click", () => activate(tab.id));
5141
+ stripEl.appendChild(chip);
5142
+ }
5143
+ const plus = document.createElement("button");
5144
+ plus.className = "view-tab-new";
5145
+ plus.textContent = "+";
5146
+ plus.title = "New tab (All Inboxes)";
5147
+ plus.addEventListener("click", () => openTab({ kind: "unified" }, "All Inboxes", true));
5148
+ stripEl.appendChild(plus);
5149
+ stripEl.hidden = tabs.length < 2;
5150
+ }
5151
+ function initTabs(strip, apply) {
5152
+ stripEl = strip;
5153
+ applyView = apply;
5154
+ try {
5155
+ const raw = sessionStorage.getItem(STORAGE_KEY);
5156
+ if (raw) {
5157
+ const parsed = JSON.parse(raw);
5158
+ if (Array.isArray(parsed?.tabs) && parsed.tabs.length) {
5159
+ tabs = parsed.tabs;
5160
+ activeId = parsed.activeId || tabs[0].id;
5161
+ for (const t of tabs) {
5162
+ const n = Number(String(t.id).replace(/^t/, ""));
5163
+ if (Number.isFinite(n) && n >= _nextId)
5164
+ _nextId = n + 1;
5165
+ }
5166
+ }
5167
+ }
5168
+ } catch {
5169
+ }
5170
+ render();
5171
+ }
5172
+ function activeTab() {
5173
+ return tabs.find((t) => t.id === activeId) || null;
5174
+ }
5175
+ function openTab(view, title, activateIt = true) {
5176
+ const tab = { id: newId(), title, view };
5177
+ tabs.push(tab);
5178
+ if (activateIt)
5179
+ activeId = tab.id;
5180
+ persist();
5181
+ render();
5182
+ if (activateIt)
5183
+ applyView(tab);
5184
+ }
5185
+ function activate(id) {
5186
+ const tab = tabs.find((t) => t.id === id);
5187
+ if (!tab || id === activeId)
5188
+ return;
5189
+ activeId = id;
5190
+ persist();
5191
+ render();
5192
+ applyView(tab);
5193
+ }
5194
+ function closeTab(id) {
5195
+ if (tabs.length < 2)
5196
+ return;
5197
+ const idx = tabs.findIndex((t) => t.id === id);
5198
+ if (idx < 0)
5199
+ return;
5200
+ const wasActive = id === activeId;
5201
+ tabs.splice(idx, 1);
5202
+ if (wasActive) {
5203
+ const next = tabs[Math.max(0, idx - 1)];
5204
+ activeId = next.id;
5205
+ persist();
5206
+ render();
5207
+ applyView(next);
5208
+ } else {
5209
+ persist();
5210
+ render();
5211
+ }
5212
+ }
5213
+ function setActiveView(view, title) {
5214
+ let tab = activeTab();
5215
+ if (!tab) {
5216
+ tab = { id: newId(), title, view };
5217
+ tabs.push(tab);
5218
+ activeId = tab.id;
5219
+ } else {
5220
+ tab.view = view;
5221
+ tab.title = title;
5222
+ }
5223
+ persist();
5224
+ render();
5225
+ }
5226
+
5227
+ // client/components/folder-tree.js
5079
5228
  var onFolderSelect;
5080
5229
  var onUnifiedInbox = null;
5081
5230
  var selectedElement;
@@ -5293,6 +5442,11 @@ function renderNode(node, container, depth) {
5293
5442
  const isTrash = node.specialUse === "trash" || node.path.toLowerCase().includes("trash");
5294
5443
  const isJunk = node.specialUse === "junk" || node.path.toLowerCase().includes("spam") || node.path.toLowerCase().includes("junk");
5295
5444
  const items = [
5445
+ { label: "Open in new tab", action: () => {
5446
+ openTab({ kind: "folder", accountId: node.accountId, folderId: node.id, specialUse: node.specialUse || "" }, node.name, true);
5447
+ } },
5448
+ { label: "", action: () => {
5449
+ }, separator: true },
5296
5450
  { label: "Mark all read", action: async () => {
5297
5451
  try {
5298
5452
  await markFolderRead(node.accountId, node.id);
@@ -6099,135 +6253,6 @@ async function updateFolderCounts() {
6099
6253
  // client/app.ts
6100
6254
  init_message_list();
6101
6255
  init_mailx_types();
6102
-
6103
- // client/components/tabs.js
6104
- var STORAGE_KEY = "mailx-view-tabs";
6105
- var tabs = [];
6106
- var activeId = "";
6107
- var stripEl = null;
6108
- var applyView = () => {
6109
- };
6110
- var _nextId = 1;
6111
- function newId() {
6112
- return `t${_nextId++}`;
6113
- }
6114
- function persist() {
6115
- try {
6116
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ tabs, activeId }));
6117
- } catch {
6118
- }
6119
- }
6120
- function render() {
6121
- if (!stripEl)
6122
- return;
6123
- stripEl.innerHTML = "";
6124
- for (const tab of tabs) {
6125
- const chip = document.createElement("div");
6126
- chip.className = "view-tab" + (tab.id === activeId ? " active" : "");
6127
- chip.dataset.tabId = tab.id;
6128
- const label = document.createElement("span");
6129
- label.className = "view-tab-label";
6130
- label.textContent = tab.title || "(view)";
6131
- chip.appendChild(label);
6132
- if (tabs.length > 1) {
6133
- const close = document.createElement("button");
6134
- close.className = "view-tab-close";
6135
- close.textContent = "\xD7";
6136
- close.title = "Close tab";
6137
- close.addEventListener("click", (e) => {
6138
- e.stopPropagation();
6139
- closeTab(tab.id);
6140
- });
6141
- chip.appendChild(close);
6142
- }
6143
- chip.addEventListener("click", () => activate(tab.id));
6144
- stripEl.appendChild(chip);
6145
- }
6146
- const plus = document.createElement("button");
6147
- plus.className = "view-tab-new";
6148
- plus.textContent = "+";
6149
- plus.title = "New tab (All Inboxes)";
6150
- plus.addEventListener("click", () => openTab({ kind: "unified" }, "All Inboxes", true));
6151
- stripEl.appendChild(plus);
6152
- stripEl.hidden = tabs.length < 2;
6153
- }
6154
- function initTabs(strip, apply) {
6155
- stripEl = strip;
6156
- applyView = apply;
6157
- try {
6158
- const raw = sessionStorage.getItem(STORAGE_KEY);
6159
- if (raw) {
6160
- const parsed = JSON.parse(raw);
6161
- if (Array.isArray(parsed?.tabs) && parsed.tabs.length) {
6162
- tabs = parsed.tabs;
6163
- activeId = parsed.activeId || tabs[0].id;
6164
- for (const t of tabs) {
6165
- const n = Number(String(t.id).replace(/^t/, ""));
6166
- if (Number.isFinite(n) && n >= _nextId)
6167
- _nextId = n + 1;
6168
- }
6169
- }
6170
- }
6171
- } catch {
6172
- }
6173
- render();
6174
- }
6175
- function activeTab() {
6176
- return tabs.find((t) => t.id === activeId) || null;
6177
- }
6178
- function openTab(view, title, activateIt = true) {
6179
- const tab = { id: newId(), title, view };
6180
- tabs.push(tab);
6181
- if (activateIt)
6182
- activeId = tab.id;
6183
- persist();
6184
- render();
6185
- if (activateIt)
6186
- applyView(tab);
6187
- }
6188
- function activate(id) {
6189
- const tab = tabs.find((t) => t.id === id);
6190
- if (!tab || id === activeId)
6191
- return;
6192
- activeId = id;
6193
- persist();
6194
- render();
6195
- applyView(tab);
6196
- }
6197
- function closeTab(id) {
6198
- if (tabs.length < 2)
6199
- return;
6200
- const idx = tabs.findIndex((t) => t.id === id);
6201
- if (idx < 0)
6202
- return;
6203
- const wasActive = id === activeId;
6204
- tabs.splice(idx, 1);
6205
- if (wasActive) {
6206
- const next = tabs[Math.max(0, idx - 1)];
6207
- activeId = next.id;
6208
- persist();
6209
- render();
6210
- applyView(next);
6211
- } else {
6212
- persist();
6213
- render();
6214
- }
6215
- }
6216
- function setActiveView(view, title) {
6217
- let tab = activeTab();
6218
- if (!tab) {
6219
- tab = { id: newId(), title, view };
6220
- tabs.push(tab);
6221
- activeId = tab.id;
6222
- } else {
6223
- tab.view = view;
6224
- tab.title = title;
6225
- }
6226
- persist();
6227
- render();
6228
- }
6229
-
6230
- // client/app.ts
6231
6256
  init_message_viewer();
6232
6257
  init_api_client();
6233
6258
  init_message_state();
@@ -6763,9 +6788,9 @@ document.getElementById("btn-factory-reset")?.addEventListener("click", async ()
6763
6788
  location.reload();
6764
6789
  }
6765
6790
  });
6766
- async function openCompose(mode) {
6791
+ async function openCompose(mode, overrideMsg, overrideAccountId) {
6767
6792
  logClientEvent("openCompose-entry", { mode });
6768
- const current = getCurrentMessage();
6793
+ const current = overrideMsg ? { message: overrideMsg, accountId: overrideAccountId || currentAccountId3 } : getCurrentMessage();
6769
6794
  if ((mode === "reply" || mode === "replyAll" || mode === "forward") && !current) {
6770
6795
  console.warn(`[compose] ${mode} \u2014 no message selected`);
6771
6796
  return;
@@ -9656,6 +9681,15 @@ function renderDiagnosticsBadge(snapshot) {
9656
9681
 
9657
9682
  ${detail}`;
9658
9683
  }
9684
+ document.addEventListener("mailx-popout-action", ((e) => {
9685
+ const { action, msg, accountId } = e.detail || {};
9686
+ if (!msg) return;
9687
+ if (action === "reply" || action === "replyAll" || action === "forward") {
9688
+ openCompose(action, msg, accountId);
9689
+ } else if (action === "delete") {
9690
+ deleteMessage(accountId, msg.uid).catch((err) => console.error(`[popout] delete failed: ${err?.message || err}`));
9691
+ }
9692
+ }));
9659
9693
  document.addEventListener("mailx-popout-message", (async (e) => {
9660
9694
  const { accountId, uid, folderId, subject } = e.detail || {};
9661
9695
  if (!accountId || !uid) return;