mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-30 12:39:20 +03:00
Merge remote-tracking branch 'origin/master' into addressbook
This commit is contained in:
commit
1a5b8819fa
204 changed files with 2050 additions and 2773 deletions
|
|
@ -38,7 +38,7 @@ export class AccountPopupView extends AbstractViewPopup {
|
|||
this.submitRequest(false);
|
||||
if (iError) {
|
||||
this.submitError(getNotification(iError));
|
||||
this.submitErrorAdditional((data && data.ErrorMessageAdditional) || '');
|
||||
this.submitErrorAdditional(data?.ErrorMessageAdditional);
|
||||
} else {
|
||||
rl.app.accountsAndIdentities();
|
||||
this.close();
|
||||
|
|
@ -54,7 +54,7 @@ export class AccountPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
onShow(account) {
|
||||
if (account && account.isAdditional()) {
|
||||
if (account?.isAdditional()) {
|
||||
this.isNew(false);
|
||||
this.email(account.email);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { koComputable } from 'External/ko';
|
||||
|
||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||
import { pString } from 'Common/Utils';
|
||||
|
||||
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||
|
||||
|
|
@ -16,6 +17,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
to: '',
|
||||
subject: '',
|
||||
text: '',
|
||||
repliedValue: -1,
|
||||
selectedDateValue: -1,
|
||||
selectedTreeValue: '',
|
||||
|
||||
|
|
@ -26,9 +28,18 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
|
||||
this.showMultisearch = koComputable(() => FolderUserStore.hasCapability('MULTISEARCH'));
|
||||
|
||||
this.repliedOptions = koComputable(() => {
|
||||
translatorTrigger();
|
||||
return [
|
||||
{ id: -1, name: '' },
|
||||
{ id: 1, name: i18n('GLOBAL/YES') },
|
||||
{ id: 0, name: i18n('GLOBAL/NO') }
|
||||
];
|
||||
});
|
||||
|
||||
this.selectedDates = koComputable(() => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_ADV_DATE_';
|
||||
let prefix = 'SEARCH/LABEL_DATE_';
|
||||
return [
|
||||
{ id: -1, name: i18n(prefix + 'ALL') },
|
||||
{ id: 3, name: i18n(prefix + '3_DAYS') },
|
||||
|
|
@ -42,7 +53,7 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
|
||||
this.selectedTree = koComputable(() => {
|
||||
translatorTrigger();
|
||||
let prefix = 'SEARCH/LABEL_ADV_SUBFOLDERS_';
|
||||
let prefix = 'SEARCH/LABEL_SUBFOLDERS_';
|
||||
return [
|
||||
{ id: '', name: i18n(prefix + 'NONE') },
|
||||
{ id: 'subtree-one', name: i18n(prefix + 'SUBTREE_ONE') },
|
||||
|
|
@ -60,66 +71,61 @@ export class AdvancedSearchPopupView extends AbstractViewPopup {
|
|||
this.close();
|
||||
}
|
||||
|
||||
parseSearchStringValue(search) {
|
||||
const parts = (search || '').split(/[\s]+/g);
|
||||
parts.forEach(part => {
|
||||
switch (part) {
|
||||
case 'has:attachment':
|
||||
this.hasAttachment(true);
|
||||
break;
|
||||
case 'is:unseen,flagged':
|
||||
this.starred(true);
|
||||
/* falls through */
|
||||
case 'is:unseen':
|
||||
this.unseen(true);
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
buildSearchString() {
|
||||
const
|
||||
self = this,
|
||||
data = new FormData(),
|
||||
append = (key, value) => value.length && data.append(key, value);
|
||||
|
||||
append('from', this.from().trim());
|
||||
append('to', this.to().trim());
|
||||
append('subject', this.subject().trim());
|
||||
append('text', this.text().trim());
|
||||
append('in', this.selectedTreeValue());
|
||||
if (-1 < this.selectedDateValue()) {
|
||||
append('from', self.from().trim());
|
||||
append('to', self.to().trim());
|
||||
append('subject', self.subject().trim());
|
||||
append('text', self.text().trim());
|
||||
append('in', self.selectedTreeValue());
|
||||
if (-1 < self.selectedDateValue()) {
|
||||
let d = new Date();
|
||||
d.setDate(d.getDate() - this.selectedDateValue());
|
||||
d.setDate(d.getDate() - self.selectedDateValue());
|
||||
append('since', d.toISOString().split('T')[0]);
|
||||
}
|
||||
|
||||
let result = new URLSearchParams(data).toString();
|
||||
|
||||
if (this.hasAttachment()) {
|
||||
if (self.hasAttachment()) {
|
||||
result += '&attachment';
|
||||
}
|
||||
if (this.unseen()) {
|
||||
if (self.unseen()) {
|
||||
result += '&unseen';
|
||||
}
|
||||
if (this.starred()) {
|
||||
if (self.starred()) {
|
||||
result += '&flagged';
|
||||
}
|
||||
if (1 == self.repliedValue()) {
|
||||
result += '&answered';
|
||||
}
|
||||
if (0 == self.repliedValue()) {
|
||||
result += '&unanswered';
|
||||
}
|
||||
|
||||
return result.replace(/^&+/, '');
|
||||
}
|
||||
|
||||
onShow(search) {
|
||||
this.from('');
|
||||
this.to('');
|
||||
this.subject('');
|
||||
this.text('');
|
||||
|
||||
this.selectedDateValue(-1);
|
||||
this.hasAttachment(false);
|
||||
this.starred(false);
|
||||
this.unseen(false);
|
||||
|
||||
this.parseSearchStringValue(search);
|
||||
const self = this,
|
||||
params = new URLSearchParams('?'+search);
|
||||
self.from(pString(params.get('from')));
|
||||
self.to(pString(params.get('to')));
|
||||
self.subject(pString(params.get('subject')));
|
||||
self.text(pString(params.get('text')));
|
||||
self.selectedTreeValue(pString(params.get('in')));
|
||||
// self.selectedDateValue(params.get('since'));
|
||||
self.selectedDateValue(-1);
|
||||
self.hasAttachment(params.has('attachment'));
|
||||
self.starred(params.has('flagged'));
|
||||
self.unseen(params.has('unseen'));
|
||||
if (params.has('answered')) {
|
||||
self.repliedValue(1);
|
||||
} else if (params.has('unanswered')) {
|
||||
self.repliedValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ export class AskPopupView extends AbstractViewPopup {
|
|||
askDesc: '',
|
||||
yesButton: '',
|
||||
noButton: '',
|
||||
username: '',
|
||||
askUsername: false,
|
||||
passphrase: '',
|
||||
askPass: false
|
||||
});
|
||||
|
|
@ -40,15 +42,19 @@ export class AskPopupView extends AbstractViewPopup {
|
|||
* @param {boolean=} focusOnShow = true
|
||||
* @returns {void}
|
||||
*/
|
||||
onShow(sAskDesc, fYesFunc = null, fNoFunc = null, focusOnShow = true, askPass = false, btnText = '') {
|
||||
onShow(sAskDesc, fYesFunc = null, fNoFunc = null, focusOnShow = true, ask = 0, btnText = '') {
|
||||
this.askDesc(sAskDesc || '');
|
||||
this.askPass(askPass);
|
||||
this.askUsername(ask & 2);
|
||||
this.askPass(ask & 1);
|
||||
this.username('');
|
||||
this.passphrase('');
|
||||
this.yesButton(i18n(btnText || 'POPUPS_ASK/BUTTON_YES'));
|
||||
this.noButton(i18n(askPass ? 'GLOBAL/CANCEL' : 'POPUPS_ASK/BUTTON_NO'));
|
||||
this.yesButton(i18n(btnText || 'GLOBAL/YES'));
|
||||
this.noButton(i18n(ask ? 'GLOBAL/CANCEL' : 'GLOBAL/NO'));
|
||||
this.fYesAction = fYesFunc;
|
||||
this.fNoAction = fNoFunc;
|
||||
this.focusOnShow = focusOnShow ? (askPass ? 'input[type="password"]' : '.buttonYes') : '';
|
||||
this.focusOnShow = focusOnShow
|
||||
? (ask ? 'input[type="'+(ask&2?'text':'password')+'"]' : '.buttonYes')
|
||||
: '';
|
||||
}
|
||||
|
||||
afterShow() {
|
||||
|
|
@ -63,12 +69,15 @@ export class AskPopupView extends AbstractViewPopup {
|
|||
onBuild() {
|
||||
// shortcuts.add('tab', 'shift', 'Ask', () => {
|
||||
shortcuts.add('tab,arrowright,arrowleft', '', 'Ask', () => {
|
||||
let btn = this.querySelector('.buttonYes');
|
||||
if (btn.matches(':focus')) {
|
||||
btn = this.querySelector('.buttonNo');
|
||||
let yes = this.querySelector('.buttonYes'),
|
||||
no = this.querySelector('.buttonNo');
|
||||
if (yes.matches(':focus')) {
|
||||
no.focus();
|
||||
return false;
|
||||
} else if (no.matches(':focus')) {
|
||||
yes.focus();
|
||||
return false;
|
||||
}
|
||||
btn.focus();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +89,20 @@ AskPopupView.password = function(sAskDesc, btnText) {
|
|||
() => resolve(this.__vm.passphrase()),
|
||||
() => resolve(null),
|
||||
true,
|
||||
true,
|
||||
1,
|
||||
btnText
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
AskPopupView.credentials = function(sAskDesc, btnText) {
|
||||
return new Promise(resolve => {
|
||||
this.showModal([
|
||||
sAskDesc,
|
||||
() => resolve({username:this.__vm.username(), password:this.__vm.passphrase()}),
|
||||
() => resolve(null),
|
||||
true,
|
||||
3,
|
||||
btnText
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ import { encodeHtml, HtmlEditor, htmlToPlain } from 'Common/Html';
|
|||
import { koArrayWithDestroy } from 'External/ko';
|
||||
|
||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||
import { messagesDeleteHelper } from 'Common/Folders';
|
||||
import { folderInformation, messagesDeleteHelper } from 'Common/Folders';
|
||||
import { serverRequest } from 'Common/Links';
|
||||
import { i18n, getNotification, getUploadErrorDescByCode, timestampToString } from 'Common/Translator';
|
||||
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
|
||||
import { Settings, SettingsCapa, SettingsGet, elementById, addShortcut } from 'Common/Globals';
|
||||
import { Settings, SettingsCapa, SettingsGet, elementById, addShortcut, createElement } from 'Common/Globals';
|
||||
//import { exitFullscreen, isFullscreen, toggleFullscreen } from 'Common/Fullscreen';
|
||||
|
||||
import { AppUserStore } from 'Stores/User/App';
|
||||
|
|
@ -50,9 +50,13 @@ import { ThemeStore } from 'Stores/Theme';
|
|||
|
||||
let alreadyFullscreen;
|
||||
*/
|
||||
let oLastMessage;
|
||||
|
||||
const
|
||||
ScopeCompose = 'Compose',
|
||||
|
||||
tpl = createElement('template'),
|
||||
|
||||
base64_encode = text => btoa(unescape(encodeURIComponent(text))).match(/.{1,76}/g).join('\r\n'),
|
||||
|
||||
email = new EmailModel(),
|
||||
|
|
@ -77,7 +81,7 @@ const
|
|||
if (FolderUserStore.currentFolderFullName() === draftsFolder) {
|
||||
MessagelistUserStore.reload(true);
|
||||
} else {
|
||||
rl.app.folderInformation(draftsFolder);
|
||||
folderInformation(draftsFolder);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -209,8 +213,8 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
super('Compose');
|
||||
|
||||
const fEmailOutInHelper = (context, identity, name, isIn) => {
|
||||
if (identity && context && identity[name]() && (isIn ? true : context[name]())) {
|
||||
const identityEmail = identity[name]();
|
||||
const identityEmail = context && identity?.[name]();
|
||||
if (identityEmail && (isIn ? true : context[name]())) {
|
||||
let list = context[name]().trim().split(',');
|
||||
|
||||
list = list.filter(email => {
|
||||
|
|
@ -218,15 +222,12 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
return email && identityEmail.trim() !== email;
|
||||
});
|
||||
|
||||
if (isIn) {
|
||||
list.push(identityEmail);
|
||||
}
|
||||
isIn && list.push(identityEmail);
|
||||
|
||||
context[name](list.join(','));
|
||||
}
|
||||
};
|
||||
|
||||
this.oLastMessage = null;
|
||||
this.oEditor = null;
|
||||
this.aDraftInfo = null;
|
||||
this.sInReplyTo = '';
|
||||
|
|
@ -352,7 +353,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
},
|
||||
|
||||
attachmentsInProcess: () => this.attachments.filter(item => item && !item.complete()),
|
||||
attachmentsInError: () => this.attachments.filter(item => item && item.error()),
|
||||
attachmentsInError: () => this.attachments.filter(item => item?.error()),
|
||||
|
||||
attachmentsCount: () => this.attachments.length,
|
||||
attachmentsInErrorCount: () => this.attachmentsInError.length,
|
||||
|
|
@ -508,7 +509,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
alternative.children.push(data);
|
||||
data = alternative;
|
||||
}
|
||||
if (sign && !draft && sign[1]) {
|
||||
if (!draft && sign?.[1]) {
|
||||
if ('openpgp' == sign[0]) {
|
||||
// Doesn't sign attachments
|
||||
params.Html = params.Text = '';
|
||||
|
|
@ -608,7 +609,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.savedErrorDesc(i18n('COMPOSE/SAVED_ERROR_ON_SEND').trim());
|
||||
} else {
|
||||
this.sendError(true);
|
||||
this.sendErrorDesc(getNotification(iError, data && data.ErrorMessage)
|
||||
this.sendErrorDesc(getNotification(iError, data?.ErrorMessage)
|
||||
|| getNotification(Notification.CantSendMessage));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -755,11 +756,11 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
|
||||
// getAutocomplete
|
||||
emailsSource(value, fResponse) {
|
||||
Remote.request('Suggestions',
|
||||
Remote.abort('Suggestions').request('Suggestions',
|
||||
(iError, data) => {
|
||||
if (!iError && isArray(data.Result)) {
|
||||
fResponse(
|
||||
data.Result.map(item => (item && item[0] ? (new EmailModel(item[0], item[1])).toLine() : null))
|
||||
data.Result.map(item => (item?.[0] ? (new EmailModel(item[0], item[1])).toLine() : null))
|
||||
.filter(v => v)
|
||||
);
|
||||
} else if (Notification.RequestAborted !== iError) {
|
||||
|
|
@ -769,15 +770,12 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
{
|
||||
Query: value
|
||||
// ,Page: 1
|
||||
},
|
||||
null,
|
||||
'',
|
||||
['Suggestions']
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
selectIdentity(identity) {
|
||||
identity = identity && identity.item;
|
||||
identity = identity?.item;
|
||||
if (identity) {
|
||||
this.currentIdentity(identity);
|
||||
this.setSignatureFromIdentity(identity);
|
||||
|
|
@ -828,7 +826,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.editor(editor => {
|
||||
let signature = identity.signature() || '',
|
||||
isHtml = ':HTML:' === signature.slice(0, 6),
|
||||
fromLine = this.oLastMessage ? emailArrayToStringLineHelper(this.oLastMessage.from, true) : '';
|
||||
fromLine = oLastMessage ? emailArrayToStringLineHelper(oLastMessage.from, true) : '';
|
||||
if (fromLine) {
|
||||
signature = signature.replace(/{{FROM-FULL}}/g, fromLine);
|
||||
if (!fromLine.includes(' ') && 0 < fromLine.indexOf('@')) {
|
||||
|
|
@ -909,24 +907,20 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
sText = '',
|
||||
identity = null,
|
||||
aDraftInfo = null,
|
||||
message = null;
|
||||
message = 1 === arrayLength(oMessageOrArray)
|
||||
? oMessageOrArray[0]
|
||||
: (isArray(oMessageOrArray) ? null : oMessageOrArray);
|
||||
|
||||
const excludeEmail = {},
|
||||
const
|
||||
// excludeEmail = new Set(),
|
||||
excludeEmail = {},
|
||||
mEmail = AccountUserStore.email(),
|
||||
lineComposeType = sType || ComposeType.Empty;
|
||||
|
||||
if (oMessageOrArray) {
|
||||
message =
|
||||
1 === arrayLength(oMessageOrArray)
|
||||
? oMessageOrArray[0]
|
||||
: isArray(oMessageOrArray)
|
||||
? null
|
||||
: oMessageOrArray;
|
||||
}
|
||||
oLastMessage = message;
|
||||
|
||||
this.oLastMessage = message;
|
||||
|
||||
if (null !== mEmail) {
|
||||
if (mEmail) {
|
||||
// excludeEmail.add(mEmail);
|
||||
excludeEmail[mEmail] = true;
|
||||
}
|
||||
|
||||
|
|
@ -934,6 +928,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
|
||||
identity = findIdentityByMessage(lineComposeType, message);
|
||||
if (identity) {
|
||||
// excludeEmail.add(identity.email());
|
||||
excludeEmail[identity.email()] = true;
|
||||
}
|
||||
|
||||
|
|
@ -1030,16 +1025,22 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
// no default
|
||||
}
|
||||
|
||||
sText = message.bodyAsHTML();
|
||||
let encrypted;
|
||||
|
||||
// https://github.com/the-djmaze/snappymail/issues/491
|
||||
tpl.innerHTML = message.bodyAsHTML();
|
||||
tpl.content.querySelectorAll('img').forEach(img =>
|
||||
img.dataset.xSrcCid || img.dataset.xSrc || img.replaceWith(img.alt || img.title)
|
||||
);
|
||||
sText = tpl.innerHTML.trim();
|
||||
|
||||
switch (lineComposeType) {
|
||||
case ComposeType.Reply:
|
||||
case ComposeType.ReplyAll:
|
||||
sFrom = message.fromToLine(false, true);
|
||||
sText = '<br><br><p>' + i18n('COMPOSE/REPLY_MESSAGE_TITLE', { DATETIME: sDate, EMAIL: sFrom })
|
||||
+ ':</p><blockquote>'
|
||||
+ sText.replace(/<img[^>]+>/g, '').replace(/<a\s[^>]+><\/a>/g, '').trim()
|
||||
+ sText.trim()
|
||||
+ '</blockquote>';
|
||||
break;
|
||||
|
||||
|
|
@ -1068,6 +1069,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
case ComposeType.ForwardAsAttachment:
|
||||
sText = '';
|
||||
break;
|
||||
|
||||
default:
|
||||
encrypted = PgpUserStore.isEncrypted(sText);
|
||||
if (encrypted) {
|
||||
|
|
@ -1131,7 +1133,8 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.setFocusInPopup();
|
||||
}
|
||||
|
||||
const downloads = this.getAttachmentsDownloadsForUpload();
|
||||
// item.CID item.isInline item.isLinked
|
||||
const downloads = this.attachments.filter(item => item && !item.tempName()).map(item => item.id);
|
||||
if (arrayLength(downloads)) {
|
||||
Remote.request('MessageUploadAttachments',
|
||||
(iError, oData) => {
|
||||
|
|
@ -1148,7 +1151,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
});
|
||||
} else {
|
||||
this.attachments.forEach(attachment => {
|
||||
if (attachment && attachment.fromMessage) {
|
||||
if (attachment?.fromMessage) {
|
||||
attachment
|
||||
.waiting(false)
|
||||
.uploading(false)
|
||||
|
|
@ -1175,7 +1178,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
if (!this.to()) {
|
||||
this.to.focused(true);
|
||||
} else if (!this.to.focused()) {
|
||||
this.oEditor && this.oEditor.focus();
|
||||
this.oEditor?.focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
|
@ -1261,7 +1264,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
})
|
||||
.on('onComplete', (id, result, data) => {
|
||||
const attachment = this.getAttachmentById(id),
|
||||
response = (data && data.Result) || {},
|
||||
response = data?.Result || {},
|
||||
errorCode = response.ErrorCode,
|
||||
attachmentJson = result && response.Attachment;
|
||||
|
||||
|
|
@ -1349,7 +1352,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
prepareAttachmentsForSendOrSave() {
|
||||
const result = {};
|
||||
this.attachments.forEach(item => {
|
||||
if (item && item.complete() && item.tempName() && item.enabled()) {
|
||||
if (item?.complete() && item?.tempName() && item?.enabled()) {
|
||||
result[item.tempName()] = [item.fileName(), item.isInline ? '1' : '0', item.CID, item.contentLocation];
|
||||
}
|
||||
});
|
||||
|
|
@ -1376,7 +1379,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
oJua || attachment.waiting(false).uploading(true);
|
||||
attachment.cancel = () => {
|
||||
this.attachments.remove(attachment);
|
||||
oJua && oJua.cancel(attachment.id);
|
||||
oJua?.cancel(attachment.id);
|
||||
};
|
||||
this.attachments.push(attachment);
|
||||
view && this.attachmentsArea();
|
||||
|
|
@ -1402,35 +1405,22 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
if (message) {
|
||||
if (ComposeType.ForwardAsAttachment === type) {
|
||||
this.addMessageAsAttachment(message);
|
||||
} else {
|
||||
} else if ([
|
||||
ComposeType.Reply, ComposeType.ReplyAll,
|
||||
ComposeType.Forward, ComposeType.Draft, ComposeType.EditAsNew
|
||||
].includes(type)) {
|
||||
message.attachments.forEach(item => {
|
||||
let add = false;
|
||||
switch (type) {
|
||||
case ComposeType.Reply:
|
||||
case ComposeType.ReplyAll:
|
||||
break;
|
||||
|
||||
case ComposeType.Forward:
|
||||
case ComposeType.Draft:
|
||||
case ComposeType.EditAsNew:
|
||||
add = true;
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
|
||||
if (add) {
|
||||
const attachment = new ComposeAttachmentModel(
|
||||
item.download,
|
||||
item.fileName,
|
||||
item.estimatedSize,
|
||||
item.isInline(),
|
||||
item.isLinked(),
|
||||
item.cid,
|
||||
item.contentLocation
|
||||
);
|
||||
attachment.fromMessage = true;
|
||||
this.addAttachment(attachment);
|
||||
}
|
||||
const attachment = new ComposeAttachmentModel(
|
||||
item.download,
|
||||
item.fileName,
|
||||
item.estimatedSize,
|
||||
item.isInline(),
|
||||
item.isLinked(),
|
||||
item.cid,
|
||||
item.contentLocation
|
||||
);
|
||||
attachment.fromMessage = true;
|
||||
this.addAttachment(attachment);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1443,7 +1433,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
isEmptyForm(includeAttachmentInProgress = true) {
|
||||
const withoutAttachment = includeAttachmentInProgress
|
||||
? !this.attachments.length
|
||||
: !this.attachments.some(item => item && item.complete());
|
||||
: !this.attachments.some(item => item?.complete());
|
||||
|
||||
return (
|
||||
!this.to.length &&
|
||||
|
|
@ -1463,8 +1453,8 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.replyTo('');
|
||||
this.subject('');
|
||||
|
||||
this.requestDsn(false);
|
||||
this.requestReadReceipt(false);
|
||||
this.requestDsn(SettingsUserStore.requestDsn());
|
||||
this.requestReadReceipt(SettingsUserStore.requestReadReceipt());
|
||||
this.markAsImportant(false);
|
||||
|
||||
this.bodyArea();
|
||||
|
|
@ -1485,8 +1475,8 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.showBcc(false);
|
||||
this.showReplyTo(false);
|
||||
|
||||
this.pgpSign(false);
|
||||
this.pgpEncrypt(false);
|
||||
this.pgpSign(SettingsUserStore.pgpSign());
|
||||
this.pgpEncrypt(SettingsUserStore.pgpEncrypt());
|
||||
|
||||
this.attachments([]);
|
||||
|
||||
|
|
@ -1499,20 +1489,11 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.sending(false);
|
||||
this.saving(false);
|
||||
|
||||
this.oEditor && this.oEditor.clear();
|
||||
this.oEditor?.clear();
|
||||
|
||||
this.dropMailvelope();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Array}
|
||||
*/
|
||||
getAttachmentsDownloadsForUpload() {
|
||||
return this.attachments.filter(item => item && !item.tempName()).map(
|
||||
item => item.id
|
||||
);
|
||||
}
|
||||
|
||||
mailvelopeArea() {
|
||||
if (!this.mailvelope) {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
contactsPaginator: computedPaginatorHelper(this.contactsPage, pagecount),
|
||||
|
||||
contactsCheckedOrSelected: () => {
|
||||
const checked = ContactUserStore.filter(item => item.checked && item.checked()),
|
||||
const checked = ContactUserStore.filter(item => item.checked?.()),
|
||||
selected = this.selectorContact();
|
||||
|
||||
return selected
|
||||
|
|
@ -128,7 +128,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
const data = oItem.getNameAndEmailHelper(),
|
||||
email = data ? new EmailModel(data[0], data[1]) : null;
|
||||
|
||||
if (email && email.validate()) {
|
||||
if (email?.validate()) {
|
||||
return email;
|
||||
}
|
||||
}
|
||||
|
|
@ -235,7 +235,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
if (this.contactsCheckedOrSelected().length) {
|
||||
Remote.request('ContactsDelete',
|
||||
(iError, oData) => {
|
||||
if (500 < (!iError && oData && oData.Time ? pInt(oData.Time) : 0)) {
|
||||
if (500 < (!iError && oData?.Time) ? pInt(oData.Time) : 0) {
|
||||
this.reloadContactList(this.bDropPageAfterDelete);
|
||||
} else {
|
||||
setTimeout(() => this.reloadContactList(this.bDropPageAfterDelete), 500);
|
||||
|
|
@ -274,7 +274,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
ContactUserStore.loading(true);
|
||||
Remote.request('Contacts',
|
||||
Remote.abort('Contacts').request('Contacts',
|
||||
(iError, data) => {
|
||||
let count = 0,
|
||||
list = [];
|
||||
|
|
@ -299,10 +299,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
Offset: offset,
|
||||
Limit: CONTACTS_PER_PAGE,
|
||||
Search: this.search()
|
||||
},
|
||||
null,
|
||||
'',
|
||||
['Contacts']
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
|||
|
||||
import { DomainAdminStore } from 'Stores/Admin/Domain';
|
||||
|
||||
import { AskPopupView } from 'View/Popup/Ask';
|
||||
|
||||
const domainToParams = oDomain => ({
|
||||
Name: oDomain.name(),
|
||||
|
||||
|
|
@ -179,39 +181,46 @@ export class DomainPopupView extends AbstractViewPopup {
|
|||
|
||||
testConnectionCommand() {
|
||||
this.clearTesting(false);
|
||||
this.testing(true);
|
||||
// https://github.com/the-djmaze/snappymail/issues/477
|
||||
AskPopupView.credentials('IMAP', 'GLOBAL/TEST').then(credentials => {
|
||||
if (credentials) {
|
||||
this.testing(true);
|
||||
const params = domainToParams(this);
|
||||
params.username = credentials.username;
|
||||
params.password = credentials.password;
|
||||
Remote.request('AdminDomainTest',
|
||||
(iError, oData) => {
|
||||
this.testing(false);
|
||||
if (iError) {
|
||||
this.testingImapError(true);
|
||||
this.testingSieveError(true);
|
||||
this.testingSmtpError(true);
|
||||
} else {
|
||||
this.testingDone(true);
|
||||
this.testingImapError(true !== oData.Result.Imap);
|
||||
this.testingSieveError(true !== oData.Result.Sieve);
|
||||
this.testingSmtpError(true !== oData.Result.Smtp);
|
||||
|
||||
Remote.request('AdminDomainTest',
|
||||
(iError, oData) => {
|
||||
this.testing(false);
|
||||
if (iError) {
|
||||
this.testingImapError(true);
|
||||
this.testingSieveError(true);
|
||||
this.testingSmtpError(true);
|
||||
} else {
|
||||
this.testingDone(true);
|
||||
this.testingImapError(true !== oData.Result.Imap);
|
||||
this.testingSieveError(true !== oData.Result.Sieve);
|
||||
this.testingSmtpError(true !== oData.Result.Smtp);
|
||||
if (this.testingImapError() && oData.Result.Imap) {
|
||||
this.testingImapErrorDesc('');
|
||||
this.testingImapErrorDesc(oData.Result.Imap);
|
||||
}
|
||||
|
||||
if (this.testingImapError() && oData.Result.Imap) {
|
||||
this.testingImapErrorDesc('');
|
||||
this.testingImapErrorDesc(oData.Result.Imap);
|
||||
}
|
||||
if (this.testingSieveError() && oData.Result.Sieve) {
|
||||
this.testingSieveErrorDesc('');
|
||||
this.testingSieveErrorDesc(oData.Result.Sieve);
|
||||
}
|
||||
|
||||
if (this.testingSieveError() && oData.Result.Sieve) {
|
||||
this.testingSieveErrorDesc('');
|
||||
this.testingSieveErrorDesc(oData.Result.Sieve);
|
||||
}
|
||||
|
||||
if (this.testingSmtpError() && oData.Result.Smtp) {
|
||||
this.testingSmtpErrorDesc('');
|
||||
this.testingSmtpErrorDesc(oData.Result.Smtp);
|
||||
}
|
||||
}
|
||||
},
|
||||
domainToParams(this)
|
||||
);
|
||||
if (this.testingSmtpError() && oData.Result.Smtp) {
|
||||
this.testingSmtpErrorDesc('');
|
||||
this.testingSmtpErrorDesc(oData.Result.Smtp);
|
||||
}
|
||||
}
|
||||
},
|
||||
params
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onDomainCreateOrSaveResponse(iError) {
|
||||
|
|
@ -239,7 +248,7 @@ export class DomainPopupView extends AbstractViewPopup {
|
|||
if (oDomain) {
|
||||
this.enableSmartPorts(false);
|
||||
this.edit(true);
|
||||
forEachObjectEntry(oDomain, (key, value) => this[key] && this[key](value));
|
||||
forEachObjectEntry(oDomain, (key, value) => this[key]?.(value));
|
||||
this.enableSmartPorts(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class FolderSystemPopupView extends AbstractViewPopup {
|
|||
|
||||
this.folderSelectList = koComputable(() =>
|
||||
folderListOptionsBuilder(
|
||||
FolderUserStore.folderListSystemNames(),
|
||||
FolderUserStore.systemFoldersNames(),
|
||||
[
|
||||
['', i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE')],
|
||||
[UNUSED_OPTION_VALUE, i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME')]
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ export class IdentityPopupView extends AbstractViewPopup {
|
|||
|
||||
submitForm() {
|
||||
if (!this.submitRequest()) {
|
||||
if (this.signature && this.signature.__fetchEditorValue) {
|
||||
this.signature.__fetchEditorValue();
|
||||
}
|
||||
this.signature?.__fetchEditorValue?.();
|
||||
|
||||
if (!this.emailHasError()) {
|
||||
this.emailHasError(!this.email().trim());
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export class LanguagesPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
changeLanguage(lang) {
|
||||
this.fLang && this.fLang(lang);
|
||||
this.fLang?.(lang);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export class OpenPgpGeneratePopupView extends AbstractViewPopup {
|
|||
|
||||
showError(e) {
|
||||
console.log(e);
|
||||
if (e && e.message) {
|
||||
if (e?.message) {
|
||||
this.submitError(e.message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,9 @@ export class LoginUserView extends AbstractViewLogin {
|
|||
if (Notification.InvalidInputArgument == iError) {
|
||||
iError = Notification.AuthError;
|
||||
}
|
||||
this.submitError(getNotification(iError, (oData ? oData.ErrorMessage : ''),
|
||||
this.submitError(getNotification(iError, oData?.ErrorMessage,
|
||||
Notification.UnknownNotification));
|
||||
this.submitErrorAdditional((oData && oData.ErrorMessageAdditional) || '');
|
||||
this.submitErrorAdditional(oData?.ErrorMessageAdditional);
|
||||
} else {
|
||||
rl.setData(oData.Result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
|
||||
this.composeInEdit = AppUserStore.composeInEdit;
|
||||
|
||||
this.folderList = FolderUserStore.folderList;
|
||||
this.folderListSystem = FolderUserStore.folderListSystem;
|
||||
this.foldersChanging = FolderUserStore.foldersChanging;
|
||||
this.systemFolders = FolderUserStore.systemFolders;
|
||||
|
||||
this.moveAction = moveAction;
|
||||
|
||||
|
|
@ -84,7 +82,7 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
}
|
||||
|
||||
el = eqs(event, 'a');
|
||||
if (el && el.matches('.selectable')) {
|
||||
if (el?.matches('.selectable')) {
|
||||
event.preventDefault();
|
||||
const folder = ko.dataFor(el);
|
||||
if (folder) {
|
||||
|
|
@ -172,10 +170,10 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
|
||||
AppUserStore.focusedState.subscribe(value => {
|
||||
let el = qs('li a.focused');
|
||||
el && el.classList.remove('focused');
|
||||
el?.classList.remove('focused');
|
||||
if (Scope.FolderList === value) {
|
||||
el = qs('li a.selected');
|
||||
el && el.classList.add('focused');
|
||||
el?.classList.add('focused');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { isFullscreen, toggleFullscreen } from 'Common/Fullscreen';
|
|||
import { mailBox, serverRequest } from 'Common/Links';
|
||||
import { Selector } from 'Common/Selector';
|
||||
|
||||
import { i18n, initOnStartOrLangChange } from 'Common/Translator';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
||||
import {
|
||||
getFolderFromCacheList,
|
||||
|
|
@ -55,14 +55,14 @@ const
|
|||
*/
|
||||
listAction = (...args) => MessagelistUserStore.setAction(...args);
|
||||
|
||||
let
|
||||
iGoToUpOrDownTimeout = 0,
|
||||
sLastSearchValue = '';
|
||||
|
||||
export class MailMessageList extends AbstractViewRight {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.emptySubjectValue = '';
|
||||
|
||||
this.iGoToUpOrDownTimeout = 0;
|
||||
|
||||
this.newMoveToFolder = !!SettingsGet('NewMoveToFolder');
|
||||
|
||||
this.allowSearch = SettingsCapa('Search');
|
||||
|
|
@ -76,19 +76,10 @@ export class MailMessageList extends AbstractViewRight {
|
|||
this.isMobile = ThemeStore.isMobile;
|
||||
this.leftPanelDisabled = leftPanelDisabled;
|
||||
|
||||
this.messageListSearch = MessagelistUserStore.listSearch;
|
||||
this.messageListError = MessagelistUserStore.error;
|
||||
|
||||
this.popupVisibility = arePopupsVisible;
|
||||
|
||||
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
|
||||
|
||||
this.messageListThreadUid = MessagelistUserStore.endThreadUid;
|
||||
|
||||
this.messageListIsLoading = MessagelistUserStore.isLoading;
|
||||
|
||||
initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'));
|
||||
|
||||
this.userUsageProc = FolderUserStore.quotaPercentage;
|
||||
|
||||
this.addObservables({
|
||||
|
|
@ -99,15 +90,13 @@ export class MailMessageList extends AbstractViewRight {
|
|||
dragOverArea: null,
|
||||
dragOverBodyArea: null,
|
||||
|
||||
inputMessageListSearchFocus: false
|
||||
focusSearch: false
|
||||
});
|
||||
|
||||
// append drag and drop
|
||||
this.dragOver = ko.observable(false).extend({ throttle: 1 });
|
||||
this.dragOverEnter = ko.observable(false).extend({ throttle: 1 });
|
||||
|
||||
this.sLastSearchValue = '';
|
||||
|
||||
this.addComputables({
|
||||
|
||||
sortSupported: () =>
|
||||
|
|
@ -136,9 +125,9 @@ export class MailMessageList extends AbstractViewRight {
|
|||
}
|
||||
},
|
||||
|
||||
inputProxyMessageListSearch: {
|
||||
inputSearch: {
|
||||
read: MessagelistUserStore.mainSearch,
|
||||
write: value => this.sLastSearchValue = value
|
||||
write: value => sLastSearchValue = value
|
||||
},
|
||||
|
||||
isIncompleteChecked: () => {
|
||||
|
|
@ -146,33 +135,28 @@ export class MailMessageList extends AbstractViewRight {
|
|||
return c && MessagelistUserStore().length > c;
|
||||
},
|
||||
|
||||
hasMessages: () => 0 < MessagelistUserStore().length,
|
||||
|
||||
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessagelistUserStore().Folder,
|
||||
|
||||
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(),
|
||||
|
||||
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessagelistUserStore().Folder,
|
||||
|
||||
isDraftFolder: () => (FolderUserStore.draftsFolder() || 0) === MessagelistUserStore().Folder,
|
||||
|
||||
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessagelistUserStore().Folder,
|
||||
archiveAllowed: () =>
|
||||
(FolderUserStore.archiveFolder() || 0) !== MessagelistUserStore().Folder
|
||||
&& UNUSED_OPTION_VALUE !== FolderUserStore.archiveFolder()
|
||||
&& !this.isDraftFolder(),
|
||||
|
||||
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessagelistUserStore().Folder,
|
||||
spamAllowed: () => UNUSED_OPTION_VALUE !== FolderUserStore.spamFolder()
|
||||
&& (FolderUserStore.sentFolder() || 0) !== MessagelistUserStore().Folder
|
||||
&& !this.isDraftFolder(),
|
||||
|
||||
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(),
|
||||
isSpamVisible: () => !this.isSpamFolder() && this.spamAllowed(),
|
||||
|
||||
isArchiveVisible: () => !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder(),
|
||||
isUnSpamVisible: () => this.isSpamFolder() && this.spamAllowed(),
|
||||
|
||||
isSpamVisible: () =>
|
||||
!this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
||||
mobileCheckedStateShow: () => ThemeStore.isMobile() ? MessagelistUserStore.listChecked().length : 1,
|
||||
|
||||
isUnSpamVisible: () =>
|
||||
this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
||||
|
||||
mobileCheckedStateShow: () => ThemeStore.isMobile() ? 0 < MessagelistUserStore.listChecked().length : true,
|
||||
|
||||
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessagelistUserStore.listChecked().length : true,
|
||||
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessagelistUserStore.listChecked().length : 1,
|
||||
|
||||
sortText: () => {
|
||||
let mode = FolderUserStore.sortMode(),
|
||||
|
|
@ -188,8 +172,6 @@ export class MailMessageList extends AbstractViewRight {
|
|||
}
|
||||
});
|
||||
|
||||
this.hasCheckedOrSelectedLines = MessagelistUserStore.hasCheckedOrSelected,
|
||||
|
||||
this.selector = new Selector(
|
||||
MessagelistUserStore,
|
||||
MessagelistUserStore.selectedMessage,
|
||||
|
|
@ -228,7 +210,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
const sFolder = e.detail.Folder, iUid = e.detail.Uid;
|
||||
|
||||
const message = MessagelistUserStore.find(
|
||||
item => item && sFolder === item.folder && iUid == item.uid
|
||||
item => sFolder === item?.folder && iUid == item?.uid
|
||||
);
|
||||
|
||||
if ('INBOX' === sFolder) {
|
||||
|
|
@ -344,7 +326,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
moveNewCommand(vm, event) {
|
||||
if (this.newMoveToFolder && this.mobileCheckedStateShow()) {
|
||||
if (vm && event && event.preventDefault) {
|
||||
if (vm && event?.preventDefault) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
|
@ -364,8 +346,8 @@ export class MailMessageList extends AbstractViewRight {
|
|||
return false;
|
||||
}
|
||||
|
||||
clearTimeout(this.iGoToUpOrDownTimeout);
|
||||
this.iGoToUpOrDownTimeout = setTimeout(() => {
|
||||
clearTimeout(iGoToUpOrDownTimeout);
|
||||
iGoToUpOrDownTimeout = setTimeout(() => {
|
||||
let prev, next, temp, current;
|
||||
|
||||
this.messageListPaginator().find(item => {
|
||||
|
|
@ -412,7 +394,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
cancelSearch() {
|
||||
MessagelistUserStore.mainSearch('');
|
||||
this.inputMessageListSearchFocus(false);
|
||||
this.focusSearch(false);
|
||||
}
|
||||
|
||||
cancelThreadUid() {
|
||||
|
|
@ -446,7 +428,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
getDragData(event) {
|
||||
const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY));
|
||||
item && item.checked && item.checked(true);
|
||||
item?.checked?.(true);
|
||||
const uids = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails();
|
||||
item && !uids.includes(item.uid) && uids.push(item.uid);
|
||||
return uids.length ? {
|
||||
|
|
@ -589,7 +571,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
}
|
||||
|
||||
gotoThread(message) {
|
||||
if (message && 0 < message.threadsLen()) {
|
||||
if (0 < message?.threadsLen()) {
|
||||
MessagelistUserStore.pageBeforeThread(MessagelistUserStore.page());
|
||||
|
||||
hasher.setHash(
|
||||
|
|
@ -643,7 +625,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
el && this.gotoThread(ko.dataFor(el));
|
||||
},
|
||||
dblclick: event => {
|
||||
let el = eqs(event, '.actionHandle');
|
||||
let el = eqs(event, '.actionHandle');
|
||||
el && this.gotoThread(ko.dataFor(el));
|
||||
}
|
||||
});
|
||||
|
|
@ -684,7 +666,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
addShortcut('enter,open', '', Scope.MessageList, () => {
|
||||
if (formFieldFocused()) {
|
||||
MessagelistUserStore.mainSearch(this.sLastSearchValue);
|
||||
MessagelistUserStore.mainSearch(sLastSearchValue);
|
||||
return false;
|
||||
}
|
||||
if (MessageUserStore.message() && this.useAutoSelect()) {
|
||||
|
|
@ -735,15 +717,10 @@ export class MailMessageList extends AbstractViewRight {
|
|||
});
|
||||
|
||||
registerShortcut('t', '', [Scope.MessageList], () => {
|
||||
let message = MessagelistUserStore.selectedMessage();
|
||||
if (!message) {
|
||||
message = MessagelistUserStore.focusedMessage();
|
||||
}
|
||||
|
||||
if (message && 0 < message.threadsLen()) {
|
||||
let message = MessagelistUserStore.selectedMessage() || MessagelistUserStore.focusedMessage();
|
||||
if (0 < message?.threadsLen()) {
|
||||
this.gotoThread(message);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
@ -778,7 +755,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
if (SettingsCapa('Search')) {
|
||||
// search input focus
|
||||
addShortcut('/', '', [Scope.MessageList, Scope.MessageView], () => {
|
||||
this.inputMessageListSearchFocus(true);
|
||||
this.focusSearch(true);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { Scope } from 'Common/Enums';
|
|||
|
||||
import {
|
||||
ComposeType,
|
||||
ClientSideKeyNameLastReplyAction,
|
||||
ClientSideKeyNameMessageHeaderFullInfo,
|
||||
ClientSideKeyNameMessageAttachmentControls,
|
||||
FolderType,
|
||||
|
|
@ -94,10 +93,11 @@ export class MailMessageView extends AbstractViewRight {
|
|||
}
|
||||
}, this.messageVisibility);
|
||||
|
||||
this.msgDefaultAction = SettingsUserStore.msgDefaultAction;
|
||||
|
||||
this.addObservables({
|
||||
showAttachmentControls: !!Local.get(ClientSideKeyNameMessageAttachmentControls),
|
||||
downloadAsZipLoading: false,
|
||||
lastReplyAction_: '',
|
||||
showFullInfo: '1' === Local.get(ClientSideKeyNameMessageHeaderFullInfo),
|
||||
moreDropdownTrigger: false,
|
||||
|
||||
|
|
@ -134,19 +134,10 @@ export class MailMessageView extends AbstractViewRight {
|
|||
allowAttachmentControls: () => arrayLength(attachmentsActions) && SettingsCapa('AttachmentsActions'),
|
||||
|
||||
downloadAsZipAllowed: () => this.attachmentsActions.includes('zip')
|
||||
&& (currentMessage() ? currentMessage().attachments : [])
|
||||
.filter(item => item && !item.isLinked() && item.checked() && item.download)
|
||||
&& (currentMessage()?.attachments || [])
|
||||
.filter(item => item?.download && !item?.isLinked() && item?.checked())
|
||||
.length,
|
||||
|
||||
lastReplyAction: {
|
||||
read: this.lastReplyAction_,
|
||||
write: value => this.lastReplyAction_(
|
||||
[ComposeType.Reply, ComposeType.ReplyAll, ComposeType.Forward].includes(value)
|
||||
? ComposeType.Reply
|
||||
: value
|
||||
)
|
||||
},
|
||||
|
||||
tagsAllowed: () => FolderUserStore.currentFolder() ? FolderUserStore.currentFolder().tagsAllowed() : false,
|
||||
|
||||
messageVisibility: () => !MessageUserStore.loading() && !!currentMessage(),
|
||||
|
|
@ -182,8 +173,6 @@ export class MailMessageView extends AbstractViewRight {
|
|||
});
|
||||
|
||||
this.addSubscribables({
|
||||
lastReplyAction_: value => Local.set(ClientSideKeyNameLastReplyAction, value),
|
||||
|
||||
message: message => {
|
||||
MessageUserStore.activeDom(null);
|
||||
|
||||
|
|
@ -207,8 +196,6 @@ export class MailMessageView extends AbstractViewRight {
|
|||
showFullInfo: value => Local.set(ClientSideKeyNameMessageHeaderFullInfo, value ? '1' : '0')
|
||||
});
|
||||
|
||||
this.lastReplyAction(Local.get(ClientSideKeyNameLastReplyAction) || ComposeType.Reply);
|
||||
|
||||
// commands
|
||||
this.replyCommand = createCommandReplyHelper(ComposeType.Reply);
|
||||
this.replyAllCommand = createCommandReplyHelper(ComposeType.ReplyAll);
|
||||
|
|
@ -256,7 +243,6 @@ export class MailMessageView extends AbstractViewRight {
|
|||
* @returns {void}
|
||||
*/
|
||||
replyOrforward(sType) {
|
||||
this.lastReplyAction(sType);
|
||||
showMessageComposer([sType, currentMessage()]);
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +286,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
el = eqs(event, '.attachmentsPlace .attachmentItem .attachmentNameParent');
|
||||
if (el) {
|
||||
const attachment = ko.dataFor(el);
|
||||
if (attachment && attachment.linkDownload()) {
|
||||
if (attachment?.linkDownload()) {
|
||||
if ('message/rfc822' == attachment.mimeType) {
|
||||
// TODO
|
||||
rl.fetch(attachment.linkDownload()).then(response => {
|
||||
|
|
@ -407,7 +393,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
// toggle message blockquotes
|
||||
registerShortcut('b', '', [Scope.MessageList, Scope.MessageView], () => {
|
||||
const message = currentMessage();
|
||||
if (message && message.body) {
|
||||
if (message?.body) {
|
||||
message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
|
||||
return false;
|
||||
}
|
||||
|
|
@ -425,7 +411,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
|
||||
// print
|
||||
addShortcut('p,printscreen', 'meta', [Scope.MessageView, Scope.MessageList], () => {
|
||||
currentMessage() && currentMessage().printMessage();
|
||||
currentMessage()?.printMessage();
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
@ -524,7 +510,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
|
||||
downloadAsZip() {
|
||||
const hashes = (currentMessage() ? currentMessage().attachments : [])
|
||||
.map(item => (item && !item.isLinked() && item.checked() ? item.download : ''))
|
||||
.map(item => item?.checked() && !item?.isLinked() ? item.download : '')
|
||||
.filter(v => v);
|
||||
if (hashes.length) {
|
||||
Remote.post('AttachmentsActions', this.downloadAsZipLoading, {
|
||||
|
|
@ -532,7 +518,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
Hashes: hashes
|
||||
})
|
||||
.then(result => {
|
||||
let hash = result && result.Result && result.Result.FileHash;
|
||||
let hash = result?.Result?.FileHash;
|
||||
if (hash) {
|
||||
download(attachmentDownload(hash), hash+'.zip');
|
||||
} else {
|
||||
|
|
@ -591,7 +577,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
if (result.data) {
|
||||
MimeToMessage(result.data, oMessage);
|
||||
oMessage.html() ? oMessage.viewHtml() : oMessage.viewPlain();
|
||||
if (result.signatures && result.signatures.length) {
|
||||
if (result.signatures?.length) {
|
||||
oMessage.pgpSigned(true);
|
||||
oMessage.pgpVerified({
|
||||
signatures: result.signatures,
|
||||
|
|
@ -610,7 +596,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
oMessage.pgpVerified(result);
|
||||
}
|
||||
/*
|
||||
if (result && result.success) {
|
||||
if (result?.success) {
|
||||
i18n('OPENPGP/GOOD_SIGNATURE', {
|
||||
USER: validKey.user + ' (' + validKey.id + ')'
|
||||
});
|
||||
|
|
@ -618,7 +604,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
} else {
|
||||
const keyIds = arrayLength(signingKeyIds) ? signingKeyIds : null,
|
||||
additional = keyIds
|
||||
? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(v => v).join(', ')
|
||||
? keyIds.map(item => item?.toHex?.()).filter(v => v).join(', ')
|
||||
: '';
|
||||
|
||||
i18n('OPENPGP/ERROR', {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class SystemDropDownUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
accountClick(account, event) {
|
||||
let email = account && account.email;
|
||||
let email = account?.email;
|
||||
if (email && 0 === event.button && AccountUserStore.email() != email) {
|
||||
AccountUserStore.loading(true);
|
||||
event.preventDefault();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue