mirror of
https://github.com/mjl-/mox.git
synced 2025-01-28 07:15:55 +03:00
webmail: for messages in designated Sent mailbox, show To/Cc/Bcc in italics, and show all correspondents in collapsed thread
showing addressees for Sent messages for issue #104 by mattfbacon, thanks for the report!
This commit is contained in:
parent
57fc37af22
commit
802dcef192
2 changed files with 118 additions and 8 deletions
|
@ -2647,6 +2647,62 @@ const newMsgitemView = (mi, msglistView, otherMailbox, listMailboxes, receivedTi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const correspondentAddrs = (miv) => {
|
||||||
|
let fromAddrs = miv.messageitem.Envelope.From || [];
|
||||||
|
let toAddrs = [];
|
||||||
|
if (listMailboxes().find(mb => mb.ID === miv.messageitem.Message.MailboxID)?.Sent) {
|
||||||
|
toAddrs = [...(miv.messageitem.Envelope.To || []), ...(miv.messageitem.Envelope.CC || []), ...(miv.messageitem.Envelope.BCC || [])];
|
||||||
|
}
|
||||||
|
return [fromAddrs, toAddrs];
|
||||||
|
};
|
||||||
|
// Correspondents for a message, possibly a collapsed thread root.
|
||||||
|
const correspondents = () => {
|
||||||
|
let fromAddrs = [];
|
||||||
|
let toAddrs = [];
|
||||||
|
if (msgitemView.isCollapsedThreadRoot()) {
|
||||||
|
// Gather both all correspondents in thread.
|
||||||
|
;
|
||||||
|
[msgitemView, ...(msgitemView.descendants())].forEach(miv => {
|
||||||
|
const [fa, ta] = correspondentAddrs(miv);
|
||||||
|
fromAddrs = [...fromAddrs, ...fa];
|
||||||
|
toAddrs = [...toAddrs, ...ta];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[fromAddrs, toAddrs] = correspondentAddrs(msgitemView);
|
||||||
|
}
|
||||||
|
const seen = new Set();
|
||||||
|
let fa = [];
|
||||||
|
let ta = [];
|
||||||
|
for (const a of fromAddrs) {
|
||||||
|
const k = a.User + '@' + a.Domain.ASCII;
|
||||||
|
if (!seen.has(k)) {
|
||||||
|
seen.add(k);
|
||||||
|
fa.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const a of toAddrs) {
|
||||||
|
const k = a.User + '@' + a.Domain.ASCII;
|
||||||
|
if (!seen.has(k)) {
|
||||||
|
seen.add(k);
|
||||||
|
ta.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let title = fa.map(a => formatAddressFull(a)).join(', ');
|
||||||
|
if (ta.length > 0) {
|
||||||
|
if (title) {
|
||||||
|
title += ',\n';
|
||||||
|
}
|
||||||
|
title += 'addressed: ' + ta.map(a => formatAddressFull(a)).join(', ');
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
attr.title(title),
|
||||||
|
join([
|
||||||
|
...fa.map(a => formatAddressShort(a)),
|
||||||
|
...ta.map(a => dom.span(style({ fontStyle: 'italic' }), formatAddressShort(a))),
|
||||||
|
], () => ', '),
|
||||||
|
];
|
||||||
|
};
|
||||||
// When rerendering, we remember active & focus states. So we don't have to make
|
// When rerendering, we remember active & focus states. So we don't have to make
|
||||||
// the caller also call redraw on MsglistView.
|
// the caller also call redraw on MsglistView.
|
||||||
const active = msgitemView.root && msgitemView.root.classList.contains('active');
|
const active = msgitemView.root && msgitemView.root.classList.contains('active');
|
||||||
|
@ -2695,9 +2751,7 @@ const newMsgitemView = (mi, msglistView, otherMailbox, listMailboxes, receivedTi
|
||||||
}
|
}
|
||||||
msglistView.threadCollapse(msgitemView);
|
msglistView.threadCollapse(msgitemView);
|
||||||
msglistView.viewportEnsureMessages();
|
msglistView.viewportEnsureMessages();
|
||||||
}) : [])), dom.div(dom._class('msgitemcell', 'msgitemfrom'), dom.div(style({ display: 'flex', justifyContent: 'space-between' }), dom.div(dom._class('msgitemfromtext', 'silenttitle'),
|
}) : [])), dom.div(dom._class('msgitemcell', 'msgitemfrom'), dom.div(style({ display: 'flex', justifyContent: 'space-between' }), dom.div(dom._class('msgitemfromtext', 'silenttitle'), correspondents()), identityHeader),
|
||||||
// todo: for collapsed messages, show all participants in thread?
|
|
||||||
attr.title((mi.Envelope.From || []).map(a => formatAddressFull(a)).join(', ')), join((mi.Envelope.From || []).map(a => formatAddressShort(a)), () => ', ')), identityHeader),
|
|
||||||
// Thread messages are connected by a vertical bar. The first and last message are
|
// Thread messages are connected by a vertical bar. The first and last message are
|
||||||
// only half the height of the item, to indicate start/end, and so it stands out
|
// only half the height of the item, to indicate start/end, and so it stands out
|
||||||
// from any thread above/below.
|
// from any thread above/below.
|
||||||
|
|
|
@ -1991,6 +1991,66 @@ const newMsgitemView = (mi: api.MessageItem, msglistView: MsglistView, otherMail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const correspondentAddrs = (miv: MsgitemView): [api.MessageAddress[], api.MessageAddress[]] => {
|
||||||
|
let fromAddrs = miv.messageitem.Envelope.From || []
|
||||||
|
let toAddrs: api.MessageAddress[] = []
|
||||||
|
if (listMailboxes().find(mb => mb.ID === miv.messageitem.Message.MailboxID)?.Sent) {
|
||||||
|
toAddrs = [...(miv.messageitem.Envelope.To || []), ...(miv.messageitem.Envelope.CC || []), ...(miv.messageitem.Envelope.BCC || [])]
|
||||||
|
}
|
||||||
|
return [fromAddrs, toAddrs]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correspondents for a message, possibly a collapsed thread root.
|
||||||
|
const correspondents = () => {
|
||||||
|
let fromAddrs: api.MessageAddress[] = []
|
||||||
|
let toAddrs: api.MessageAddress[] = []
|
||||||
|
if (msgitemView.isCollapsedThreadRoot()) {
|
||||||
|
// Gather both all correspondents in thread.
|
||||||
|
;[msgitemView, ...(msgitemView.descendants())].forEach(miv => {
|
||||||
|
const [fa, ta] = correspondentAddrs(miv)
|
||||||
|
fromAddrs = [...fromAddrs, ...fa]
|
||||||
|
toAddrs = [...toAddrs, ...ta]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
[fromAddrs, toAddrs] = correspondentAddrs(msgitemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set<string>()
|
||||||
|
let fa: api.MessageAddress[] = []
|
||||||
|
let ta: api.MessageAddress[] = []
|
||||||
|
for (const a of fromAddrs) {
|
||||||
|
const k = a.User+'@'+a.Domain.ASCII
|
||||||
|
if (!seen.has(k)) {
|
||||||
|
seen.add(k)
|
||||||
|
fa.push(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const a of toAddrs) {
|
||||||
|
const k = a.User+'@'+a.Domain.ASCII
|
||||||
|
if (!seen.has(k)) {
|
||||||
|
seen.add(k)
|
||||||
|
ta.push(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let title = fa.map(a => formatAddressFull(a)).join(', ')
|
||||||
|
if (ta.length > 0) {
|
||||||
|
if (title) {
|
||||||
|
title += ',\n'
|
||||||
|
}
|
||||||
|
title += 'addressed: '+ta.map(a => formatAddressFull(a)).join(', ')
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
attr.title(title),
|
||||||
|
join(
|
||||||
|
[
|
||||||
|
...fa.map(a => formatAddressShort(a)),
|
||||||
|
...ta.map(a => dom.span(style({fontStyle: 'italic'}), formatAddressShort(a))),
|
||||||
|
],
|
||||||
|
() => ', '
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
// When rerendering, we remember active & focus states. So we don't have to make
|
// When rerendering, we remember active & focus states. So we don't have to make
|
||||||
// the caller also call redraw on MsglistView.
|
// the caller also call redraw on MsglistView.
|
||||||
const active = msgitemView.root && msgitemView.root.classList.contains('active')
|
const active = msgitemView.root && msgitemView.root.classList.contains('active')
|
||||||
|
@ -2053,11 +2113,7 @@ const newMsgitemView = (mi: api.MessageItem, msglistView: MsglistView, otherMail
|
||||||
),
|
),
|
||||||
dom.div(dom._class('msgitemcell', 'msgitemfrom'),
|
dom.div(dom._class('msgitemcell', 'msgitemfrom'),
|
||||||
dom.div(style({display: 'flex', justifyContent: 'space-between'}),
|
dom.div(style({display: 'flex', justifyContent: 'space-between'}),
|
||||||
dom.div(dom._class('msgitemfromtext', 'silenttitle'),
|
dom.div(dom._class('msgitemfromtext', 'silenttitle'), correspondents()),
|
||||||
// todo: for collapsed messages, show all participants in thread?
|
|
||||||
attr.title((mi.Envelope.From || []).map(a => formatAddressFull(a)).join(', ')),
|
|
||||||
join((mi.Envelope.From || []).map(a => formatAddressShort(a)), () => ', ')
|
|
||||||
),
|
|
||||||
identityHeader,
|
identityHeader,
|
||||||
),
|
),
|
||||||
// Thread messages are connected by a vertical bar. The first and last message are
|
// Thread messages are connected by a vertical bar. The first and last message are
|
||||||
|
|
Loading…
Reference in a new issue