Improved messages cache handling and fixed broken messagesBodiesDom

This commit is contained in:
the-djmaze 2023-02-20 10:49:22 +01:00
parent 15f9aa11db
commit 4fb359be59
7 changed files with 124 additions and 135 deletions

View file

@ -5,7 +5,6 @@ import { doc, createElement, elementById, dropdowns, dropdownVisibility, Setting
import { plainToHtml } from 'Common/Html'; import { plainToHtml } from 'Common/Html';
import { getNotification } from 'Common/Translator'; import { getNotification } from 'Common/Translator';
import { EmailCollectionModel } from 'Model/EmailCollection'; import { EmailCollectionModel } from 'Model/EmailCollection';
import { MessageModel } from 'Model/Message';
import { MessageUserStore } from 'Stores/User/Message'; import { MessageUserStore } from 'Stores/User/Message';
import { MessagelistUserStore } from 'Stores/User/Messagelist'; import { MessagelistUserStore } from 'Stores/User/Messagelist';
import { SettingsUserStore } from 'Stores/User/Settings'; import { SettingsUserStore } from 'Stores/User/Settings';
@ -246,75 +245,80 @@ setLayoutResizer = (source, sClientSideKeyName, mode) =>
} }
}, },
viewMessage = (oMessage, popup) => {
if (popup) {
oMessage.viewPopupMessage();
} else {
MessageUserStore.error('');
let id = 'rl-msg-' + oMessage.hash,
body = oMessage.body || elementById(id);
if (!body) {
body = createElement('div',{
id:id,
hidden:'',
class:'b-text-part'
+ (oMessage.pgpSigned() ? ' openpgp-signed' : '')
+ (oMessage.pgpEncrypted() ? ' openpgp-encrypted' : '')
});
MessageUserStore.purgeCache();
}
body.message = oMessage;
oMessage.body = body;
if (!SettingsUserStore.viewHTML() || !oMessage.viewHtml()) {
oMessage.viewPlain();
}
MessageUserStore.bodiesDom().append(body);
MessageUserStore.loading(false);
oMessage.body.hidden = false;
if (oMessage.isUnseen()) {
MessageUserStore.MessageSeenTimer = setTimeout(
() => MessagelistUserStore.setAction(oMessage.folder, MessageSetAction.SetSeen, [oMessage]),
SettingsUserStore.messageReadDelay() * 1000 // seconds
);
}
}
},
populateMessageBody = (oMessage, popup) => { populateMessageBody = (oMessage, popup) => {
if (oMessage) { if (oMessage) {
popup || MessageUserStore.message(oMessage); popup || MessageUserStore.message(oMessage);
popup || MessageUserStore.loading(true); if (oMessage.body) {
Remote.message((iError, oData/*, bCached*/) => { viewMessage(oMessage, popup);
if (iError) { } else {
if (Notification.RequestAborted !== iError && !popup) { popup || MessageUserStore.loading(true);
MessageUserStore.message(null); Remote.message((iError, oData/*, bCached*/) => {
MessageUserStore.error(getNotification(iError)); if (iError) {
} if (Notification.RequestAborted !== iError && !popup) {
} else { MessageUserStore.message(null);
let json = oData?.Result; MessageUserStore.error(getNotification(iError));
if (json }
&& MessageModel.validJson(json) } else {
&& oMessage.hash === json.hash let json = oData?.Result;
// && oMessage.folder === json.folder if (json
// && oMessage.uid == json.uid && oMessage.hash === json.hash
&& oMessage.revivePropertiesFromJson(json) // && oMessage.folder === json.folder
) { // && oMessage.uid == json.uid
&& oMessage.revivePropertiesFromJson(json)
) {
/* /*
if (bCached) { if (bCached) {
delete json.flags; delete json.flags;
}
*/
if (popup) {
oMessage.viewPopupMessage();
} else {
MessageUserStore.error('');
const messagesDom = MessageUserStore.bodiesDom();
if (messagesDom) {
let id = 'rl-msg-' + oMessage.hash,
body = elementById(id);
if (body) {
oMessage.body = body;
oMessage.isHtml(body.classList.contains('html'));
oMessage.hasImages(body.rlHasImages);
} else {
body = createElement('div',{
id:id,
hidden:'',
class:'b-text-part'
+ (oMessage.pgpSigned() ? ' openpgp-signed' : '')
+ (oMessage.pgpEncrypted() ? ' openpgp-encrypted' : '')
});
oMessage.body = body;
if (!SettingsUserStore.viewHTML() || !oMessage.viewHtml()) {
oMessage.viewPlain();
}
MessageUserStore.purgeMessageBodyCache();
}
messagesDom.append(body);
oMessage.body.hidden = false;
} }
} oMessage.body.remove();
*/
viewMessage(oMessage, popup);
MessageFlagsCache.initMessage(oMessage); MessageFlagsCache.initMessage(oMessage);
if (oMessage.isUnseen()) {
MessageUserStore.MessageSeenTimer = setTimeout(
() => MessagelistUserStore.setAction(oMessage.folder, MessageSetAction.SetSeen, [oMessage]),
SettingsUserStore.messageReadDelay() * 1000 // seconds
);
} }
} }
} popup || MessageUserStore.loading(false);
popup || MessageUserStore.loading(false); }, oMessage.folder, oMessage.uid);
}, oMessage.folder, oMessage.uid); }
} }
}; };

View file

@ -290,49 +290,46 @@ export class MessageModel extends AbstractModel {
return [[...toResult.values()], [...ccResult.values()]]; return [[...toResult.values()], [...ccResult.values()]];
} }
viewHtml() { viewBody(html) {
const body = this.body; const body = this.body;
if (body && this.html()) { if (body) {
let result = msgHtml(this); if (html) {
this.hasExternals(result.hasExternals); let result = msgHtml(this);
this.hasImages(body.rlHasImages = !!result.hasExternals); this.hasExternals(result.hasExternals);
this.hasImages(!!result.hasExternals);
body.innerHTML = result.html; body.innerHTML = result.html;
if (!this.isSpam() && FolderUserStore.spamFolder() != this.folder) {
body.classList.toggle('html', 1); if ('always' === SettingsUserStore.viewImages()) {
body.classList.toggle('plain', 0); this.showExternalImages();
}
if (!this.isSpam() && FolderUserStore.spamFolder() != this.folder) { if ('match' === SettingsUserStore.viewImages()) {
if ('always' === SettingsUserStore.viewImages()) { this.showExternalImages(1);
this.showExternalImages(); }
}
if ('match' === SettingsUserStore.viewImages()) {
this.showExternalImages(1);
} }
} else {
body.innerHTML = plainToHtml(
(this.plain()
? this.plain()
.replace(/-----BEGIN PGP (SIGNED MESSAGE-----(\r?\n[a-z][^\r\n]+)+|SIGNATURE-----[\s\S]*)/, '')
.trim()
: htmlToPlain(body.innerHTML)
)
);
this.hasImages(false);
} }
body.classList.toggle('html', html);
this.isHtml(true); body.classList.toggle('plain', !html);
this.isHtml(html);
return true; return true;
} }
} }
viewHtml() {
return this.html() && this.viewBody(true);
}
viewPlain() { viewPlain() {
const body = this.body; return this.viewBody(false);
if (body) {
body.classList.toggle('html', 0);
body.classList.toggle('plain', 1);
body.innerHTML = plainToHtml(
(this.plain()
? this.plain()
.replace(/-----BEGIN PGP (SIGNED MESSAGE-----(\r?\n[a-z][^\r\n]+)+|SIGNATURE-----[\s\S]*)/, '')
.trim()
: htmlToPlain(body.innerHTML)
)
);
this.isHtml(false);
this.hasImages(false);
return true;
}
} }
viewPopupMessage(print) { viewPopupMessage(print) {
@ -447,7 +444,6 @@ export class MessageModel extends AbstractModel {
}); });
this.hasImages(hasImages); this.hasImages(hasImages);
body.rlHasImages = hasImages;
} }
} }

View file

@ -17,7 +17,6 @@ import { LanguageStore } from 'Stores/Language';
import { SettingsUserStore } from 'Stores/User/Settings'; import { SettingsUserStore } from 'Stores/User/Settings';
import { IdentityUserStore } from 'Stores/User/Identity'; import { IdentityUserStore } from 'Stores/User/Identity';
import { NotificationUserStore } from 'Stores/User/Notification'; import { NotificationUserStore } from 'Stores/User/Notification';
import { MessageUserStore } from 'Stores/User/Message';
import { MessagelistUserStore } from 'Stores/User/Messagelist'; import { MessagelistUserStore } from 'Stores/User/Messagelist';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';
@ -102,7 +101,7 @@ export class UserSettingsGeneral extends AbstractViewSettings {
this.addSetting('Layout'); this.addSetting('Layout');
this.addSetting('MaxBlockquotesLevel'); this.addSetting('MaxBlockquotesLevel');
this.addSettings(['ViewHTML', 'ViewImages', 'ViewImagesWhitelist', 'HideDeleted', 'AllowStyles', this.addSettings(['ViewHTML', 'ViewImages', 'ViewImagesWhitelist', 'HideDeleted', 'RemoveColors', 'AllowStyles',
'ListInlineAttachments', 'simpleAttachmentsList', 'UseCheckboxesInList', 'listGrouped', 'ReplySameFolder', 'ListInlineAttachments', 'simpleAttachmentsList', 'UseCheckboxesInList', 'listGrouped', 'ReplySameFolder',
'requestReadReceipt', 'requestDsn', 'requireTLS', 'pgpSign', 'pgpEncrypt', 'allowSpellcheck', 'requestReadReceipt', 'requestDsn', 'requireTLS', 'pgpSign', 'pgpEncrypt', 'allowSpellcheck',
'DesktopNotifications', 'SoundNotification', 'CollapseBlockquotes', 'AllowDraftAutosave']); 'DesktopNotifications', 'SoundNotification', 'CollapseBlockquotes', 'AllowDraftAutosave']);
@ -123,14 +122,6 @@ export class UserSettingsGeneral extends AbstractViewSettings {
hourCycle: value => hourCycle: value =>
Remote.saveSetting('hourCycle', value), Remote.saveSetting('hourCycle', value),
removeColors: value => {
let dom = MessageUserStore.bodiesDom();
if (dom) {
dom.innerHTML = '';
}
Remote.saveSetting('RemoveColors', value);
},
notificationSound: value => { notificationSound: value => {
Remote.saveSetting('NotificationSound', value); Remote.saveSetting('NotificationSound', value);
Settings.set('NotificationSound', value); Settings.set('NotificationSound', value);

View file

@ -30,25 +30,21 @@ export const MessageUserStore = new class {
AppUserStore.focusedState(Scope.MessageList); AppUserStore.focusedState(Scope.MessageList);
exitFullscreen(); exitFullscreen();
} }
this.hideMessageBodies(); [...(this.bodiesDom()?.children || [])].forEach(el => el.hidden = true);
}, },
}); });
this.purgeMessageBodyCache = this.purgeMessageBodyCache.throttle(30000); this.purgeCache = this.purgeCache.throttle(30000);
} }
purgeMessageBodyCache() { purgeCache(all) {
const messagesDom = this.bodiesDom(), const children = this.bodiesDom()?.children || [];
children = messagesDom?.children; let i = Math.max(0, children.length - (all ? 0 : 15));
if (children) { while (i--) {
while (15 < children.length) { children[i].remove();
children[0].remove(); if (children[i].message) {
children[i].message.body = null;
} }
} }
} }
hideMessageBodies() {
const messagesDom = this.bodiesDom();
messagesDom && Array.from(messagesDom.children).forEach(el => el.hidden = true);
}
}; };

View file

@ -128,7 +128,6 @@ export class MailMessageView extends AbstractViewRight {
this.message = currentMessage; this.message = currentMessage;
this.messageLoadingThrottle = MessageUserStore.loading; this.messageLoadingThrottle = MessageUserStore.loading;
this.messagesBodiesDom = MessageUserStore.bodiesDom;
this.messageError = MessageUserStore.error; this.messageError = MessageUserStore.error;
this.fullScreenMode = isFullscreen; this.fullScreenMode = isFullscreen;
@ -166,7 +165,7 @@ export class MailMessageView extends AbstractViewRight {
listAttachments: () => currentMessage()?.attachments() listAttachments: () => currentMessage()?.attachments()
.filter(item => SettingsUserStore.listInlineAttachments() || !item.isLinked()), .filter(item => SettingsUserStore.listInlineAttachments() || !item.isLinked()),
hasAttachments: () => this.listAttachments().length, hasAttachments: () => this.listAttachments()?.length,
canBeRepliedOrForwarded: () => !MessagelistUserStore.isDraftFolder() && this.messageVisibility(), canBeRepliedOrForwarded: () => !MessagelistUserStore.isDraftFolder() && this.messageVisibility(),
@ -459,6 +458,8 @@ export class MailMessageView extends AbstractViewRight {
} }
return false; return false;
}); });
MessageUserStore.bodiesDom(dom.querySelector('.bodyText'));
} }
scrollMessageToTop() { scrollMessageToTop() {

View file

@ -70,9 +70,8 @@ export class SystemDropDownUserView extends AbstractViewRight {
/* // Not working yet /* // Not working yet
forEachObjectEntry(oData.Result, (key, value) => rl.settings.set(key, value)); forEachObjectEntry(oData.Result, (key, value) => rl.settings.set(key, value));
clearCache(); clearCache();
// MessageUserStore.setMessage(); // MessageUserStore.message();
// MessageUserStore.purgeMessageBodyCache(); // MessageUserStore.purgeCache();
// MessageUserStore.hideMessageBodies();
MessagelistUserStore([]); MessagelistUserStore([]);
// FolderUserStore.folderList([]); // FolderUserStore.folderList([]);
loadFolders(value => { loadFolders(value => {

View file

@ -30,8 +30,7 @@
<div class="b-message-view-desc" data-i18n="MESSAGE/MESSAGE_VIEW_DESC" data-bind="visible: !message() && '' === messageError() && !hasCheckedMessages()"> <div class="b-message-view-desc" data-i18n="MESSAGE/MESSAGE_VIEW_DESC" data-bind="visible: !message() && '' === messageError() && !hasCheckedMessages()">
</div> </div>
<!-- ko if: message --> <div class="b-message" data-bind="visible: message, css: message()?.lineAsCss(0)">
<div class="b-message" data-bind="i18nUpdate: message, css: message()?.lineAsCss(0)">
<div class="message-fixed-button-toolbar"> <div class="message-fixed-button-toolbar">
<a class="btn btn-success buttonEdit fontastic hide-mobile" data-bind="visible: isDraftFolder(), command: editCommand">🖉</a> <a class="btn btn-success buttonEdit fontastic hide-mobile" data-bind="visible: isDraftFolder(), command: editCommand">🖉</a>
<div class="btn-group" style="margin-right: -8px; display: inline;"> <div class="btn-group" style="margin-right: -8px; display: inline;">
@ -121,7 +120,7 @@
</div> </div>
</div> </div>
<div class="messageItemHeader"> <div class="messageItemHeader" data-bind="if: message, i18nUpdate: message">
<div class="subjectParent"> <div class="subjectParent">
<span class="infoParent g-ui-user-select-none fontastic" data-bind="click: toggleFullInfo"></span> <span class="infoParent g-ui-user-select-none fontastic" data-bind="click: toggleFullInfo"></span>
<span class="flagParent g-ui-user-select-none flagOff fontastic" data-bind="text: message().isFlagged() ? '★' : '☆', css: {'flagOn': message().isFlagged(), 'flagOff': !message().isFlagged()}"></span> <span class="flagParent g-ui-user-select-none flagOff fontastic" data-bind="text: message().isFlagged() ? '★' : '☆', css: {'flagOn': message().isFlagged(), 'flagOff': !message().isFlagged()}"></span>
@ -176,7 +175,7 @@
</div> </div>
</div> </div>
<div id="messageItem"> <div id="messageItem">
<div class="messageItemHeader"> <div class="messageItemHeader" data-bind="if: message, i18nUpdate: message">
<div data-bind="hidden: showFullInfo"> <div data-bind="hidden: showFullInfo">
<time class="date" data-moment-format="FULL" data-bind="visible: 0 < message().dateTimeStampInUTC(), moment: message().dateTimeStampInUTC()"></time> <time class="date" data-moment-format="FULL" data-bind="visible: 0 < message().dateTimeStampInUTC(), moment: message().dateTimeStampInUTC()"></time>
<div class="informationShortWrp"> <div class="informationShortWrp">
@ -223,7 +222,7 @@
</div> </div>
<div data-bind="hidden: messageLoadingThrottle"> <div data-bind="hidden: messageLoadingThrottle">
<div class="bodySubHeader"> <div class="bodySubHeader" data-bind="if: message, i18nUpdate: message">
<div class="readReceipt" data-bind="visible: askReadReceipt, click: readReceipt" <div class="readReceipt" data-bind="visible: askReadReceipt, click: readReceipt"
data-icon="✉" data-i18n="MESSAGE/BUTTON_NOTIFY_READ_RECEIPT"></div> data-icon="✉" data-i18n="MESSAGE/BUTTON_NOTIFY_READ_RECEIPT"></div>
<details class="attachmentsPlace" data-bind="visible: hasAttachments, css: {'selection-mode' : showAttachmentControls}"> <details class="attachmentsPlace" data-bind="visible: hasAttachments, css: {'selection-mode' : showAttachmentControls}">
@ -294,19 +293,22 @@
</div> </div>
</div> </div>
<div class="openpgp-control encrypted" data-bind="visible: message().pgpEncrypted(), css: {'success': message().pgpDecrypted()}"> <!-- ko if: message()?.pgpEncrypted() -->
<div class="openpgp-control encrypted" data-bind="i18nUpdate: message, css: {'success': message().pgpDecrypted()}">
<span data-icon="🔒" data-i18n="OPENPGP/ENCRYPTED_MESSAGE"></span> <span data-icon="🔒" data-i18n="OPENPGP/ENCRYPTED_MESSAGE"></span>
<button class="btn" data-bind="visible: pgpSupported, click: pgpDecrypt" data-i18n="OPENPGP/BUTTON_DECRYPT"></button> <button class="btn" data-bind="visible: pgpSupported, click: pgpDecrypt" data-i18n="OPENPGP/BUTTON_DECRYPT"></button>
</div> </div>
<div class="openpgp-control signed" data-bind="visible: message().pgpSigned(), css: {'success': message().pgpVerified() && message().pgpVerified().success, 'error': message().pgpVerified() && !message().pgpVerified().success}"> <!-- /ko -->
<!-- ko if: message()?.pgpSigned() -->
<div class="openpgp-control signed" data-bind="i18nUpdate: message, css: {'success': message().pgpVerified() && message().pgpVerified().success, 'error': message().pgpVerified() && !message().pgpVerified().success}">
<span data-icon="✍" data-i18n="OPENPGP/SIGNED_MESSAGE"></span> <span data-icon="✍" data-i18n="OPENPGP/SIGNED_MESSAGE"></span>
<button class="btn" data-bind="visible: pgpSupported, click: pgpVerify" data-i18n="OPENPGP/BUTTON_VERIFY"></button> <button class="btn" data-bind="visible: pgpSupported, click: pgpVerify" data-i18n="OPENPGP/BUTTON_VERIFY"></button>
</div> </div>
<!-- /ko -->
<div class="bodyText" data-bind="initDom: messagesBodiesDom"></div> <div class="bodyText"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- /ko -->
</div> </div>