@bobfrankston/rmfmail 1.2.261 → 1.2.263
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 +51 -18
- package/client/app.bundle.js.map +2 -2
- package/client/components/message-viewer.js +73 -20
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +80 -18
- package/client/package.json +1 -1
- package/client/styles/components.css +45 -1
- package/package.json +3 -3
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-62112 → node_modules.npmglobalize-stash-88864}/.package-lock.json +0 -0
|
@@ -1339,19 +1339,7 @@ export async function showMessage(accountId, uid, folderId, specialUse, isRetry
|
|
|
1339
1339
|
const fromEl = headerEl.querySelector(".mv-from");
|
|
1340
1340
|
const toEl = headerEl.querySelector(".mv-to");
|
|
1341
1341
|
fromEl.textContent = formatAddr(msg.from);
|
|
1342
|
-
|
|
1343
|
-
if (msg.cc?.length)
|
|
1344
|
-
toLine += ` Cc: ${msg.cc.map(formatAddr).join(", ")}`;
|
|
1345
|
-
// Always-visible Delivered-To line — shown when present and not already
|
|
1346
|
-
// covered by the To/Cc list. Critical for accounts with multiple aliases
|
|
1347
|
-
// where you need to see which one received the message at a glance.
|
|
1348
|
-
const toAddrs = (msg.to || []).map((a) => a.address.toLowerCase());
|
|
1349
|
-
const ccAddrs = (msg.cc || []).map((a) => a.address.toLowerCase());
|
|
1350
|
-
const dt = (msg.deliveredTo || "").toLowerCase();
|
|
1351
|
-
if (msg.deliveredTo && !toAddrs.includes(dt) && !ccAddrs.includes(dt)) {
|
|
1352
|
-
toLine += ` Delivered-To: ${msg.deliveredTo}`;
|
|
1353
|
-
}
|
|
1354
|
-
toEl.textContent = toLine;
|
|
1342
|
+
setRecipientLine(toEl, msg.to, msg.cc, msg.deliveredTo);
|
|
1355
1343
|
headerEl.querySelector(".mv-subject").textContent = msg.subject;
|
|
1356
1344
|
document.dispatchEvent(new CustomEvent("mailx-message-shown", { detail: { accountId } }));
|
|
1357
1345
|
// Right-click on email addresses in header: copy name, copy address,
|
|
@@ -1361,7 +1349,12 @@ export async function showMessage(accountId, uid, folderId, specialUse, isRetry
|
|
|
1361
1349
|
e.preventDefault();
|
|
1362
1350
|
const me = e;
|
|
1363
1351
|
const items = [];
|
|
1364
|
-
const
|
|
1352
|
+
const allAddrs = el === fromEl ? [msg.from] : [...(msg.to || []), ...(msg.cc || [])];
|
|
1353
|
+
// Bulk mail can address hundreds of people; enumerating every
|
|
1354
|
+
// one builds a menu thousands of items tall. Show the first
|
|
1355
|
+
// few and say how many were left out.
|
|
1356
|
+
const addrs = allAddrs.slice(0, CONTEXT_MENU_ADDR_CAP);
|
|
1357
|
+
const omitted = allAddrs.length - addrs.length;
|
|
1365
1358
|
for (const addr of addrs) {
|
|
1366
1359
|
if (!addr?.address)
|
|
1367
1360
|
continue;
|
|
@@ -1452,6 +1445,13 @@ export async function showMessage(accountId, uid, folderId, specialUse, isRetry
|
|
|
1452
1445
|
});
|
|
1453
1446
|
items.push({ label: "", action: () => { }, separator: true });
|
|
1454
1447
|
}
|
|
1448
|
+
if (omitted > 0) {
|
|
1449
|
+
items.push({
|
|
1450
|
+
label: `… ${omitted} more recipients — copy the whole list`,
|
|
1451
|
+
action: () => navigator.clipboard.writeText(allAddrs.map(formatAddr).join(", ")),
|
|
1452
|
+
});
|
|
1453
|
+
items.push({ label: "", action: () => { }, separator: true });
|
|
1454
|
+
}
|
|
1455
1455
|
items.push({ label: "Reply", action: () => document.dispatchEvent(new CustomEvent("mailx-compose", { detail: { mode: "reply" } })) });
|
|
1456
1456
|
items.push({ label: "Reply All", action: () => document.dispatchEvent(new CustomEvent("mailx-compose", { detail: { mode: "replyAll" } })) });
|
|
1457
1457
|
items.push({ label: "Forward", action: () => document.dispatchEvent(new CustomEvent("mailx-compose", { detail: { mode: "forward" } })) });
|
|
@@ -2311,6 +2311,63 @@ function formatAddr(addr) {
|
|
|
2311
2311
|
return `${addr.name} <${addr.address}>`;
|
|
2312
2312
|
return addr.address;
|
|
2313
2313
|
}
|
|
2314
|
+
/** Above this many To+Cc addresses the recipient line is offered collapsed
|
|
2315
|
+
* with a "▸ N recipients" expander. Anything under it reads fine inline. */
|
|
2316
|
+
const MANY_RECIPIENTS = 6;
|
|
2317
|
+
/** Ceiling on how many addresses the header's right-click menu enumerates.
|
|
2318
|
+
* Each address contributes ~7 entries (copy name / copy address / contacts /
|
|
2319
|
+
* preferred / denylist / priority), so a 444-recipient bulk mail would build
|
|
2320
|
+
* a 3000-item menu taller than the screen and slow to open. */
|
|
2321
|
+
const CONTEXT_MENU_ADDR_CAP = 12;
|
|
2322
|
+
/**
|
|
2323
|
+
* Fill the viewer's To/Cc line.
|
|
2324
|
+
*
|
|
2325
|
+
* Written as elements rather than a bare `textContent` because bulk mail can
|
|
2326
|
+
* carry hundreds of recipients: the full text stays in the DOM (so find,
|
|
2327
|
+
* select and copy still see every address) but `.mv-to-text` is line-clamped
|
|
2328
|
+
* to two rows, with a toggle to expand. Unclamped, that one line grew the
|
|
2329
|
+
* header past the whole viewer height and starved `.mv-body` to zero — see
|
|
2330
|
+
* the `.mv-header` comment in components.css.
|
|
2331
|
+
*/
|
|
2332
|
+
function setRecipientLine(toEl, to, cc, deliveredTo) {
|
|
2333
|
+
const toList = to || [];
|
|
2334
|
+
const ccList = cc || [];
|
|
2335
|
+
let line = `To: ${toList.map(formatAddr).join(", ")}`;
|
|
2336
|
+
if (ccList.length)
|
|
2337
|
+
line += ` Cc: ${ccList.map(formatAddr).join(", ")}`;
|
|
2338
|
+
// Always-visible Delivered-To — shown when present and not already covered
|
|
2339
|
+
// by the To/Cc list. Critical for accounts with multiple aliases where you
|
|
2340
|
+
// need to see which one received the message at a glance.
|
|
2341
|
+
if (deliveredTo) {
|
|
2342
|
+
const dt = deliveredTo.toLowerCase();
|
|
2343
|
+
const covered = [...toList, ...ccList].some(a => a.address.toLowerCase() === dt);
|
|
2344
|
+
if (!covered)
|
|
2345
|
+
line += ` Delivered-To: ${deliveredTo}`;
|
|
2346
|
+
}
|
|
2347
|
+
toEl.textContent = "";
|
|
2348
|
+
toEl.classList.remove("mv-to-expanded");
|
|
2349
|
+
const text = document.createElement("span");
|
|
2350
|
+
text.className = "mv-to-text";
|
|
2351
|
+
text.textContent = line;
|
|
2352
|
+
toEl.append(text);
|
|
2353
|
+
const count = toList.length + ccList.length;
|
|
2354
|
+
// Offer the expander when the list is long by count, or when the clamp
|
|
2355
|
+
// actually cut something off (a handful of very long display names).
|
|
2356
|
+
const clamped = text.scrollHeight > text.clientHeight + 1;
|
|
2357
|
+
if (count <= MANY_RECIPIENTS && !clamped)
|
|
2358
|
+
return;
|
|
2359
|
+
const toggle = document.createElement("button");
|
|
2360
|
+
toggle.className = "mv-to-toggle";
|
|
2361
|
+
toggle.type = "button";
|
|
2362
|
+
const label = count === 1 ? "1 recipient" : `${count} recipients`;
|
|
2363
|
+
const paint = (open) => {
|
|
2364
|
+
toggle.textContent = `${open ? "▾" : "▸"} ${label}`;
|
|
2365
|
+
toggle.title = open ? "Collapse the recipient list" : "Show the full recipient list";
|
|
2366
|
+
};
|
|
2367
|
+
paint(false);
|
|
2368
|
+
toggle.addEventListener("click", () => paint(toEl.classList.toggle("mv-to-expanded")));
|
|
2369
|
+
toEl.append(toggle);
|
|
2370
|
+
}
|
|
2314
2371
|
/** Render the viewer header from a list-row envelope (instant — no body
|
|
2315
2372
|
* fetch awaited). Used to populate the header pane the moment a message
|
|
2316
2373
|
* is clicked so the user always sees something actionable; getMessage()
|
|
@@ -2325,12 +2382,8 @@ function renderHeaderFromEnvelope(headerEl, env) {
|
|
|
2325
2382
|
const dateEl = headerEl.querySelector(".mv-date");
|
|
2326
2383
|
if (fromEl)
|
|
2327
2384
|
fromEl.textContent = formatAddr(env.from);
|
|
2328
|
-
if (toEl)
|
|
2329
|
-
|
|
2330
|
-
if (env.cc?.length)
|
|
2331
|
-
toLine += ` Cc: ${env.cc.map(formatAddr).join(", ")}`;
|
|
2332
|
-
toEl.textContent = toLine;
|
|
2333
|
-
}
|
|
2385
|
+
if (toEl)
|
|
2386
|
+
setRecipientLine(toEl, env.to, env.cc);
|
|
2334
2387
|
if (subjEl)
|
|
2335
2388
|
subjEl.textContent = env.subject || "";
|
|
2336
2389
|
if (dateEl) {
|