@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.
- package/client/app.bundle.js +166 -132
- package/client/app.bundle.js.map +3 -3
- package/client/app.js +23 -3
- package/client/app.js.map +1 -1
- package/client/app.ts +22 -2
- package/client/components/folder-tree.js +5 -0
- package/client/components/folder-tree.js.map +1 -1
- package/client/components/folder-tree.ts +9 -0
- package/client/components/message-viewer.js +24 -1
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +25 -1
- package/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-58712 → node_modules.npmglobalize-stash-28848}/.package-lock.json +0 -0
package/client/app.bundle.js
CHANGED
|
@@ -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
|
-
|
|
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;
|