mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-02 14:07:04 +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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue