mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-29 20:19:22 +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
|
|
@ -12,7 +12,7 @@ export class AbstractCollectionModel extends Array
|
|||
}
|
||||
|
||||
onDestroy() {
|
||||
this.forEach(item => item.onDestroy && item.onDestroy());
|
||||
this.forEach(item => item.onDestroy?.());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { encodeHtml } from 'Common/Html';
|
||||
|
||||
import { AbstractModel } from 'Knoin/AbstractModel';
|
||||
|
||||
|
|
@ -284,7 +283,7 @@ export class EmailModel extends AbstractModel {
|
|||
*/
|
||||
static reviveFromJson(json) {
|
||||
const email = super.reviveFromJson(json);
|
||||
email && email.clearDuplicateName();
|
||||
email?.clearDuplicateName();
|
||||
return email;
|
||||
}
|
||||
|
||||
|
|
@ -333,45 +332,13 @@ export class EmailModel extends AbstractModel {
|
|||
|
||||
/**
|
||||
* @param {boolean} friendlyView = false
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} useEncodeHtml = false
|
||||
* @returns {string}
|
||||
*/
|
||||
toLine(friendlyView, wrapWithLink, useEncodeHtml) {
|
||||
let result = '',
|
||||
toLink = (to, txt) => '<a href="mailto:' + to + '" target="_blank" tabindex="-1">' + encodeHtml(txt) + '</a>';
|
||||
if (this.email) {
|
||||
if (friendlyView && this.name) {
|
||||
result = wrapWithLink
|
||||
? toLink(
|
||||
encodeHtml(this.email) + '?to=' + encodeURIComponent('"' + this.name + '" <' + this.email + '>'),
|
||||
this.name
|
||||
)
|
||||
: (useEncodeHtml ? encodeHtml(this.name) : this.name);
|
||||
} else {
|
||||
result = this.email;
|
||||
if (this.name) {
|
||||
if (wrapWithLink) {
|
||||
result =
|
||||
encodeHtml('"' + this.name + '" <')
|
||||
+ toLink(
|
||||
encodeHtml(this.email) + '?to=' + encodeURIComponent('"' + this.name + '" <' + this.email + '>'),
|
||||
result
|
||||
)
|
||||
+ encodeHtml('>');
|
||||
} else {
|
||||
result = '"' + this.name + '" <' + result + '>';
|
||||
if (useEncodeHtml) {
|
||||
result = encodeHtml(result);
|
||||
}
|
||||
}
|
||||
} else if (wrapWithLink) {
|
||||
result = toLink(encodeHtml(this.email), this.email);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
toLine(friendlyView) {
|
||||
let result = this.email;
|
||||
return (result && this.name)
|
||||
? (friendlyView ? this.name : '"' + this.name + '" <' + result + '>')
|
||||
: result;
|
||||
}
|
||||
|
||||
static splitEmailLine(line) {
|
||||
|
|
@ -384,7 +351,7 @@ export class EmailModel extends AbstractModel {
|
|||
? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '')
|
||||
: null;
|
||||
|
||||
if (address && address.email) {
|
||||
if (address?.email) {
|
||||
exists = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export class EmailCollectionModel extends AbstractCollectionModel
|
|||
toStringClear() {
|
||||
const result = [];
|
||||
this.forEach(email => {
|
||||
if (email && email.email && email.name) {
|
||||
if (email?.email && email?.name) {
|
||||
result.push(email.email);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ export const
|
|||
.post('Folders', FolderUserStore.foldersLoading)
|
||||
.then(data => {
|
||||
data = FolderCollectionModel.reviveFromJson(data.Result);
|
||||
data && data.storeIt();
|
||||
fCallback && fCallback(true);
|
||||
data?.storeIt();
|
||||
fCallback?.(true);
|
||||
// Repeat every 15 minutes?
|
||||
// this.foldersTimeout = setTimeout(loadFolders, 900000);
|
||||
})
|
||||
|
|
@ -128,7 +128,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
*/
|
||||
static reviveFromJson(object) {
|
||||
const expandedFolders = Local.get(ClientSideKeyNameExpandedFolders);
|
||||
if (object && object.SystemFolders) {
|
||||
if (object?.SystemFolders) {
|
||||
forEachObjectEntry(SystemFolders, key =>
|
||||
SystemFolders[key] = SettingsGet(key+'Folder') || object.SystemFolders[FolderType[key]]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import ko from 'ko';
|
|||
import { MessagePriority } from 'Common/EnumsUser';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
||||
import { doc } from 'Common/Globals';
|
||||
import { doc, SettingsGet } from 'Common/Globals';
|
||||
import { encodeHtml, plainToHtml, cleanHtml } from 'Common/Html';
|
||||
import { isArray, arrayLength, forEachObjectEntry } from 'Common/Utils';
|
||||
import { serverRequestRaw } from 'Common/Links';
|
||||
import { serverRequestRaw, proxy } from 'Common/Links';
|
||||
|
||||
import { FolderUserStore } from 'Stores/User/Folder';
|
||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||
|
|
@ -89,11 +89,15 @@ const
|
|||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {EmailCollectionModel} emails
|
||||
* @param {Object} unic
|
||||
* @param {Map} localEmails
|
||||
*/
|
||||
replyHelper = (emails, unic, localEmails) => {
|
||||
emails.forEach(email => {
|
||||
if (undefined === unic[email.email]) {
|
||||
unic[email.email] = true;
|
||||
localEmails.push(email);
|
||||
if (!unic[email.email] && !localEmails.has(email.email)) {
|
||||
localEmails.set(email.email, email);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -319,7 +323,7 @@ export class MessageModel extends AbstractModel {
|
|||
*/
|
||||
fromDkimData() {
|
||||
let result = ['none', ''];
|
||||
if (1 === arrayLength(this.from) && this.from[0] && this.from[0].dkimStatus) {
|
||||
if (1 === arrayLength(this.from) && this.from[0]?.dkimStatus) {
|
||||
result = [this.from[0].dkimStatus, this.from[0].dkimValue || ''];
|
||||
}
|
||||
|
||||
|
|
@ -375,7 +379,6 @@ export class MessageModel extends AbstractModel {
|
|||
focused: this.focused(),
|
||||
important: this.isImportant(),
|
||||
withAttachments: !!this.attachments().length,
|
||||
emptySubject: !this.subject(),
|
||||
// hasChildrenMessage: 1 < this.threadsLen(),
|
||||
hasUnseenSubMessage: this.hasUnseenSubMessage(),
|
||||
hasFlaggedSubMessage: this.hasFlaggedSubMessage()
|
||||
|
|
@ -396,7 +399,7 @@ export class MessageModel extends AbstractModel {
|
|||
* @returns {string}
|
||||
*/
|
||||
fromAsSingleEmail() {
|
||||
return isArray(this.from) && this.from[0] ? this.from[0].email : '';
|
||||
return (isArray(this.from) && this.from[0]?.email) || '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -415,50 +418,36 @@ export class MessageModel extends AbstractModel {
|
|||
|
||||
/**
|
||||
* @param {Object} excludeEmails
|
||||
* @param {boolean=} last = false
|
||||
* @returns {Array}
|
||||
*/
|
||||
replyEmails(excludeEmails, last) {
|
||||
const result = [],
|
||||
unic = undefined === excludeEmails ? {} : excludeEmails;
|
||||
|
||||
replyEmails(excludeEmails) {
|
||||
const
|
||||
result = new Map(),
|
||||
unic = excludeEmails || {};
|
||||
replyHelper(this.replyTo, unic, result);
|
||||
if (!result.length) {
|
||||
replyHelper(this.from, unic, result);
|
||||
}
|
||||
|
||||
if (!result.length && !last) {
|
||||
return this.replyEmails({}, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
result.size || replyHelper(this.from, unic, result);
|
||||
return result.size ? [...result.values()] : [this.to[0]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} excludeEmails
|
||||
* @param {boolean=} last = false
|
||||
* @returns {Array.<Array>}
|
||||
*/
|
||||
replyAllEmails(excludeEmails, last) {
|
||||
let data = [];
|
||||
const toResult = [],
|
||||
ccResult = [],
|
||||
unic = undefined === excludeEmails ? {} : excludeEmails;
|
||||
replyAllEmails(excludeEmails) {
|
||||
const
|
||||
toResult = new Map(),
|
||||
ccResult = new Map(),
|
||||
unic = excludeEmails || {};
|
||||
|
||||
replyHelper(this.replyTo, unic, toResult);
|
||||
if (!toResult.length) {
|
||||
if (!toResult.size) {
|
||||
replyHelper(this.from, unic, toResult);
|
||||
}
|
||||
|
||||
replyHelper(this.to, unic, toResult);
|
||||
|
||||
replyHelper(this.cc, unic, ccResult);
|
||||
|
||||
if (!toResult.length && !last) {
|
||||
data = this.replyAllEmails({}, true);
|
||||
return [data[0], ccResult];
|
||||
}
|
||||
|
||||
return [toResult, ccResult];
|
||||
return [[...toResult.values()], [...ccResult.values()]];
|
||||
}
|
||||
|
||||
viewHtml() {
|
||||
|
|
@ -617,16 +606,18 @@ export class MessageModel extends AbstractModel {
|
|||
this.hasImages(false);
|
||||
body.rlHasImages = false;
|
||||
|
||||
let attr = 'data-x-src';
|
||||
body.querySelectorAll('[' + attr + ']').forEach(node => {
|
||||
if (node.matches('img')) {
|
||||
node.loading = 'lazy';
|
||||
}
|
||||
node.src = node.getAttribute(attr);
|
||||
let attr = 'data-x-src',
|
||||
src, useProxy = !!SettingsGet('UseLocalProxyForExternalImages');
|
||||
body.querySelectorAll('img[' + attr + ']').forEach(node => {
|
||||
node.loading = 'lazy';
|
||||
src = node.getAttribute(attr);
|
||||
node.src = useProxy ? proxy(src) : src;
|
||||
});
|
||||
|
||||
body.querySelectorAll('[data-x-style-url]').forEach(node => {
|
||||
JSON.parse(node.dataset.xStyleUrl).forEach(data => node.style[data[0]] = "url('" + data[1] + "')");
|
||||
JSON.parse(node.dataset.xStyleUrl).forEach(data =>
|
||||
node.style[data[0]] = "url('" + (useProxy ? proxy(data[1]) : data[1]) + "')"
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue