mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-24 16:14:01 +08:00
270 lines
6.9 KiB
TypeScript
270 lines
6.9 KiB
TypeScript
/* eslint global-require: 0*/
|
|
import _ from 'underscore';
|
|
import {
|
|
localized,
|
|
Thread,
|
|
Actions,
|
|
Message,
|
|
TaskFactory,
|
|
DatabaseStore,
|
|
FocusedPerspectiveStore,
|
|
} from 'mailspring-exports';
|
|
|
|
type TemplateItem =
|
|
| {
|
|
label: string;
|
|
click: () => void;
|
|
}
|
|
| { type: 'separator' };
|
|
|
|
export default class ThreadListContextMenu {
|
|
threadIds: string[];
|
|
accountIds: string[];
|
|
threads?: Thread[];
|
|
|
|
constructor({ threadIds = [], accountIds = [] }) {
|
|
this.threadIds = threadIds;
|
|
this.accountIds = accountIds;
|
|
}
|
|
|
|
menuItemTemplate() {
|
|
return DatabaseStore.modelify<Thread>(Thread, this.threadIds)
|
|
.then(threads => {
|
|
this.threads = threads;
|
|
|
|
return Promise.all<TemplateItem>([
|
|
this.findWithFrom(),
|
|
this.findWithSubject(),
|
|
{ type: 'separator' },
|
|
this.replyItem(),
|
|
this.replyAllItem(),
|
|
this.forwardItem(),
|
|
{ type: 'separator' },
|
|
this.archiveItem(),
|
|
this.trashItem(),
|
|
this.markAsReadItem(),
|
|
this.markAsSpamItem(),
|
|
this.starItem(),
|
|
{ type: 'separator' },
|
|
this.createMailboxLinkItem(),
|
|
]);
|
|
})
|
|
.then(menuItems => {
|
|
return _.filter(_.compact(menuItems), (item, index) => {
|
|
if (
|
|
(index === 0 || index === menuItems.length - 1) &&
|
|
(item as any).type === 'separator'
|
|
) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
});
|
|
}
|
|
|
|
findWithFrom(): TemplateItem | null {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
const first = this.threads[0];
|
|
const from = first.participants.find(p => !p.isMe()) || first.participants[0];
|
|
|
|
return {
|
|
label: localized(`Search for`) + ' ' + from.email,
|
|
click: () => {
|
|
Actions.searchQuerySubmitted(`"${from.email.replace('"', '""')}"`);
|
|
},
|
|
};
|
|
}
|
|
|
|
findWithSubject(): TemplateItem | null {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
const subject = this.threads[0].subject;
|
|
|
|
return {
|
|
label:
|
|
localized(`Search for`) +
|
|
' ' +
|
|
(subject.length > 35 ? `${subject.substr(0, 35)}...` : subject),
|
|
click: () => {
|
|
Actions.searchQuerySubmitted(`subject:"${subject}"`);
|
|
},
|
|
};
|
|
}
|
|
|
|
replyItem(): TemplateItem | null {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
return {
|
|
label: localized('Reply'),
|
|
click: () => {
|
|
Actions.composeReply({
|
|
threadId: this.threadIds[0],
|
|
popout: true,
|
|
type: 'reply',
|
|
behavior: 'prefer-existing-if-pristine',
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
replyAllItem(): Promise<TemplateItem> | null {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
|
|
return DatabaseStore.findBy<Message>(Message, { threadId: this.threadIds[0] })
|
|
.order(Message.attributes.date.descending())
|
|
.limit(1)
|
|
.then(message => {
|
|
if (message && message.canReplyAll()) {
|
|
return {
|
|
label: localized('Reply All'),
|
|
click: () => {
|
|
Actions.composeReply({
|
|
threadId: this.threadIds[0],
|
|
popout: true,
|
|
type: 'reply-all',
|
|
behavior: 'prefer-existing-if-pristine',
|
|
});
|
|
},
|
|
};
|
|
}
|
|
return null;
|
|
});
|
|
}
|
|
|
|
forwardItem(): TemplateItem | null {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
return {
|
|
label: localized('Forward'),
|
|
click: () => {
|
|
Actions.composeForward({ threadId: this.threadIds[0], popout: true });
|
|
},
|
|
};
|
|
}
|
|
|
|
archiveItem(): TemplateItem | null {
|
|
const perspective = FocusedPerspectiveStore.current();
|
|
const allowed = perspective.canArchiveThreads(this.threads);
|
|
if (!allowed) {
|
|
return null;
|
|
}
|
|
return {
|
|
label: localized('Archive'),
|
|
click: () => {
|
|
const tasks = TaskFactory.tasksForArchiving({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
});
|
|
Actions.queueTasks(tasks);
|
|
},
|
|
};
|
|
}
|
|
|
|
trashItem(): TemplateItem | null {
|
|
const perspective = FocusedPerspectiveStore.current();
|
|
const allowed = perspective.canMoveThreadsTo(this.threads, 'trash');
|
|
if (!allowed) {
|
|
return null;
|
|
}
|
|
return {
|
|
label: localized('Trash'),
|
|
click: () => {
|
|
const tasks = TaskFactory.tasksForMovingToTrash({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
});
|
|
Actions.queueTasks(tasks);
|
|
},
|
|
};
|
|
}
|
|
|
|
markAsReadItem(): TemplateItem | null {
|
|
const unread = this.threads.every(t => t.unread === false);
|
|
const dir = unread ? localized('Unread') : localized('Read');
|
|
|
|
return {
|
|
label: localized(`Mark as %@`, dir),
|
|
click: () => {
|
|
Actions.queueTask(
|
|
TaskFactory.taskForInvertingUnread({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
})
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
markAsSpamItem(): TemplateItem | null {
|
|
const allInSpam = this.threads.every(item => item.folders.some(c => c.role === 'spam'));
|
|
const dir = allInSpam ? localized('Not Spam') : localized('Spam');
|
|
|
|
return {
|
|
label: localized(`Mark as %@`, dir),
|
|
click: () => {
|
|
Actions.queueTasks(
|
|
allInSpam
|
|
? TaskFactory.tasksForMarkingNotSpam({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
})
|
|
: TaskFactory.tasksForMarkingAsSpam({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
})
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
starItem(): TemplateItem | null {
|
|
const starred = this.threads.every(t => t.starred === false);
|
|
|
|
let label = localized('Star');
|
|
if (!starred) {
|
|
label = this.threadIds.length > 1 ? localized('Remove Stars') : localized('Remove Star');
|
|
}
|
|
|
|
return {
|
|
label: label,
|
|
click: () => {
|
|
Actions.queueTask(
|
|
TaskFactory.taskForInvertingStarred({
|
|
source: 'Context Menu: Thread List',
|
|
threads: this.threads,
|
|
})
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
createMailboxLinkItem() {
|
|
if (this.threadIds.length !== 1 || !this.threads[0]) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
label: localized('Copy mailbox permalink'),
|
|
click: async () => {
|
|
const id = this.threadIds[0];
|
|
const thread = await DatabaseStore.findBy<Thread>(Thread, { id }).limit(1);
|
|
if (!thread) return;
|
|
require('electron').clipboard.writeText(thread.getMailboxPermalink());
|
|
},
|
|
};
|
|
}
|
|
|
|
displayMenu() {
|
|
const { remote } = require('electron');
|
|
this.menuItemTemplate().then(template => {
|
|
remote.Menu.buildFromTemplate(template).popup({});
|
|
});
|
|
}
|
|
}
|