mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-03-03 18:28:48 +08:00
Restructure JavaScript
Split list code from MessageUserStore into MessagelistUserStore Move functions out of AppUser
This commit is contained in:
parent
60b7f61e42
commit
661cd2aaf9
26 changed files with 1144 additions and 1186 deletions
326
dev/App/User.js
326
dev/App/User.js
|
@ -1,17 +1,15 @@
|
||||||
import 'External/User/ko';
|
import 'External/User/ko';
|
||||||
|
|
||||||
import { isArray, arrayLength, pString, forEachObjectValue } from 'Common/Utils';
|
import { isArray, pString } from 'Common/Utils';
|
||||||
import { mailToHelper, setLayoutResizer } from 'Common/UtilsUser';
|
import { mailToHelper, setLayoutResizer } from 'Common/UtilsUser';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Notification,
|
|
||||||
Scope
|
Scope
|
||||||
} from 'Common/Enums';
|
} from 'Common/Enums';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FolderType,
|
FolderType,
|
||||||
SetSystemFoldersNotification,
|
SetSystemFoldersNotification,
|
||||||
MessageSetAction,
|
|
||||||
ClientSideKeyName
|
ClientSideKeyName
|
||||||
} from 'Common/EnumsUser';
|
} from 'Common/EnumsUser';
|
||||||
|
|
||||||
|
@ -34,9 +32,7 @@ import {
|
||||||
getFolderFromCacheList
|
getFolderFromCacheList
|
||||||
} from 'Common/Cache';
|
} from 'Common/Cache';
|
||||||
|
|
||||||
import { mailBox } from 'Common/Links';
|
import { i18n, reloadTime } from 'Common/Translator';
|
||||||
|
|
||||||
import { getNotification, i18n } from 'Common/Translator';
|
|
||||||
|
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { NotificationUserStore } from 'Stores/User/Notification';
|
import { NotificationUserStore } from 'Stores/User/Notification';
|
||||||
|
@ -45,12 +41,11 @@ import { ContactUserStore } from 'Stores/User/Contact';
|
||||||
import { IdentityUserStore } from 'Stores/User/Identity';
|
import { IdentityUserStore } from 'Stores/User/Identity';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { PgpUserStore } from 'Stores/User/Pgp';
|
import { PgpUserStore } from 'Stores/User/Pgp';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
import { EmailModel } from 'Model/Email';
|
|
||||||
import { AccountModel } from 'Model/Account';
|
import { AccountModel } from 'Model/Account';
|
||||||
import { IdentityModel } from 'Model/Identity';
|
import { IdentityModel } from 'Model/Identity';
|
||||||
|
|
||||||
|
@ -66,24 +61,16 @@ import { ComposePopupView } from 'View/Popup/Compose';
|
||||||
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
|
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
|
||||||
import { AskPopupView } from 'View/Popup/Ask';
|
import { AskPopupView } from 'View/Popup/Ask';
|
||||||
|
|
||||||
import { timeToNode } from 'Common/Momentor';
|
import { folderInformationMultiply, refreshFoldersInterval, messagesMoveHelper, messagesDeleteHelper } from 'Common/Folders';
|
||||||
|
import { loadFolders } from 'Model/FolderCollection';
|
||||||
// Every 5 minutes
|
|
||||||
const refreshFolders = 300000;
|
|
||||||
|
|
||||||
let moveCache = {};
|
|
||||||
|
|
||||||
class AppUser extends AbstractApp {
|
class AppUser extends AbstractApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(Remote);
|
super(Remote);
|
||||||
|
|
||||||
this.moveOrDeleteResponseHelper = this.moveOrDeleteResponseHelper.bind(this);
|
|
||||||
|
|
||||||
this.messagesMoveTrigger = this.messagesMoveTrigger.debounce(500);
|
|
||||||
|
|
||||||
// wakeUp
|
// wakeUp
|
||||||
const interval = 3600000; // 60m
|
const interval = 3600000; // 60m
|
||||||
var lastTime = Date.now();
|
let lastTime = Date.now();
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
if (currentTime > (lastTime + interval + 1000)) {
|
if (currentTime > (lastTime + interval + 1000)) {
|
||||||
|
@ -105,126 +92,6 @@ class AppUser extends AbstractApp {
|
||||||
(Settings.app('inIframe') ? parent : window).location.reload();
|
(Settings.app('inIframe') ? parent : window).location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean=} bDropPagePosition = false
|
|
||||||
* @param {boolean=} bDropCurrenFolderCache = false
|
|
||||||
*/
|
|
||||||
reloadMessageList(bDropPagePosition = false, bDropCurrenFolderCache = false) {
|
|
||||||
let iOffset = (MessageUserStore.listPage() - 1) * SettingsUserStore.messagesPerPage();
|
|
||||||
|
|
||||||
if (bDropCurrenFolderCache) {
|
|
||||||
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bDropPagePosition) {
|
|
||||||
MessageUserStore.listPage(1);
|
|
||||||
MessageUserStore.listPageBeforeThread(1);
|
|
||||||
iOffset = 0;
|
|
||||||
|
|
||||||
rl.route.setHash(
|
|
||||||
mailBox(
|
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
|
||||||
MessageUserStore.listPage(),
|
|
||||||
MessageUserStore.listSearch(),
|
|
||||||
MessageUserStore.listThreadUid()
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageUserStore.listLoading(true);
|
|
||||||
MessageUserStore.listError('');
|
|
||||||
Remote.messageList(
|
|
||||||
(iError, oData, bCached) => {
|
|
||||||
if (iError) {
|
|
||||||
if (Notification.RequestAborted !== iError) {
|
|
||||||
MessageUserStore.list([]);
|
|
||||||
MessageUserStore.listError(getNotification(iError));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MessageUserStore.setMessageList(oData, bCached);
|
|
||||||
}
|
|
||||||
MessageUserStore.listLoading(false);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Folder: FolderUserStore.currentFolderFullName(),
|
|
||||||
Offset: iOffset,
|
|
||||||
Limit: SettingsUserStore.messagesPerPage(),
|
|
||||||
Search: MessageUserStore.listSearch(),
|
|
||||||
ThreadUid: MessageUserStore.listThreadUid()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
messagesMoveTrigger() {
|
|
||||||
const sTrashFolder = FolderUserStore.trashFolder(),
|
|
||||||
sSpamFolder = FolderUserStore.spamFolder();
|
|
||||||
|
|
||||||
forEachObjectValue(moveCache, item => {
|
|
||||||
const isSpam = sSpamFolder === item.To,
|
|
||||||
isTrash = sTrashFolder === item.To,
|
|
||||||
isHam = !isSpam && sSpamFolder === item.From && getFolderInboxName() === item.To;
|
|
||||||
|
|
||||||
Remote.request('MessageMove',
|
|
||||||
this.moveOrDeleteResponseHelper,
|
|
||||||
{
|
|
||||||
FromFolder: item.From,
|
|
||||||
ToFolder: item.To,
|
|
||||||
Uids: item.Uid.join(','),
|
|
||||||
MarkAsRead: (isSpam || isTrash) ? 1 : 0,
|
|
||||||
Learning: isSpam ? 'SPAM' : isHam ? 'HAM' : ''
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
'',
|
|
||||||
['MessageList']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
moveCache = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
messagesMoveHelper(fromFolderFullName, toFolderFullName, uidsForMove) {
|
|
||||||
const hash = '$$' + fromFolderFullName + '$$' + toFolderFullName + '$$';
|
|
||||||
if (!moveCache[hash]) {
|
|
||||||
moveCache[hash] = {
|
|
||||||
From: fromFolderFullName,
|
|
||||||
To: toFolderFullName,
|
|
||||||
Uid: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
moveCache[hash].Uid = moveCache[hash].Uid.concat(uidsForMove).unique();
|
|
||||||
this.messagesMoveTrigger();
|
|
||||||
}
|
|
||||||
|
|
||||||
messagesDeleteHelper(sFromFolderFullName, aUidForRemove) {
|
|
||||||
Remote.request('MessageDelete',
|
|
||||||
this.moveOrDeleteResponseHelper,
|
|
||||||
{
|
|
||||||
Folder: sFromFolderFullName,
|
|
||||||
Uids: aUidForRemove.join(',')
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
'',
|
|
||||||
['MessageList']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveOrDeleteResponseHelper(iError, oData) {
|
|
||||||
if (iError) {
|
|
||||||
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
|
||||||
alert(getNotification(iError));
|
|
||||||
} else if (FolderUserStore.currentFolder()) {
|
|
||||||
if (2 === arrayLength(oData.Result)) {
|
|
||||||
setFolderHash(oData.Result[0], oData.Result[1]);
|
|
||||||
} else {
|
|
||||||
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
|
||||||
}
|
|
||||||
this.reloadMessageList(!MessageUserStore.list.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} iDeleteType
|
* @param {number} iDeleteType
|
||||||
* @param {string} sFromFolderFullName
|
* @param {string} sFromFolderFullName
|
||||||
|
@ -276,46 +143,16 @@ class AppUser extends AbstractApp {
|
||||||
showScreenPopup(AskPopupView, [
|
showScreenPopup(AskPopupView, [
|
||||||
i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'),
|
i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'),
|
||||||
() => {
|
() => {
|
||||||
this.messagesDeleteHelper(sFromFolderFullName, aUidForRemove);
|
messagesDeleteHelper(sFromFolderFullName, aUidForRemove);
|
||||||
MessageUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove);
|
MessagelistUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove);
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
} else if (oMoveFolder) {
|
} else if (oMoveFolder) {
|
||||||
this.messagesMoveHelper(sFromFolderFullName, oMoveFolder.fullName, aUidForRemove);
|
messagesMoveHelper(sFromFolderFullName, oMoveFolder.fullName, aUidForRemove);
|
||||||
MessageUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove, oMoveFolder.fullName);
|
MessagelistUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove, oMoveFolder.fullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} sFromFolderFullName
|
|
||||||
* @param {Array} aUidForMove
|
|
||||||
* @param {string} sToFolderFullName
|
|
||||||
* @param {boolean=} bCopy = false
|
|
||||||
*/
|
|
||||||
moveMessagesToFolder(sFromFolderFullName, aUidForMove, sToFolderFullName, bCopy) {
|
|
||||||
if (sFromFolderFullName !== sToFolderFullName && arrayLength(aUidForMove)) {
|
|
||||||
const oFromFolder = getFolderFromCacheList(sFromFolderFullName),
|
|
||||||
oToFolder = getFolderFromCacheList(sToFolderFullName);
|
|
||||||
|
|
||||||
if (oFromFolder && oToFolder) {
|
|
||||||
if (undefined === bCopy ? false : !!bCopy) {
|
|
||||||
Remote.request('MessageCopy', null, {
|
|
||||||
FromFolder: oFromFolder.fullName,
|
|
||||||
ToFolder: oToFolder.fullName,
|
|
||||||
Uids: aUidForMove.join(',')
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.messagesMoveHelper(oFromFolder.fullName, oToFolder.fullName, aUidForMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageUserStore.removeMessagesFromList(oFromFolder.fullName, aUidForMove, oToFolder.fullName, bCopy);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
accountsAndIdentities() {
|
accountsAndIdentities() {
|
||||||
AccountUserStore.loading(true);
|
AccountUserStore.loading(true);
|
||||||
IdentityUserStore.loading(true);
|
IdentityUserStore.loading(true);
|
||||||
|
@ -396,10 +233,10 @@ class AppUser extends AbstractApp {
|
||||||
MessageFlagsCache.setFor(folderFromCache.fullName, message.Uid.toString(), message.Flags)
|
MessageFlagsCache.setFor(folderFromCache.fullName, message.Uid.toString(), message.Flags)
|
||||||
);
|
);
|
||||||
|
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageUserStore.initUidNextAndNewMessages(
|
MessagelistUserStore.initUidNextAndNewMessages(
|
||||||
folderFromCache.fullName,
|
folderFromCache.fullName,
|
||||||
result.UidNext,
|
result.UidNext,
|
||||||
result.NewMessages
|
result.NewMessages
|
||||||
|
@ -407,7 +244,7 @@ class AppUser extends AbstractApp {
|
||||||
|
|
||||||
if (!hash || unreadCountChange || result.Hash !== hash) {
|
if (!hash || unreadCountChange || result.Hash !== hash) {
|
||||||
if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) {
|
if (folderFromCache.fullName === FolderUserStore.currentFolderFullName()) {
|
||||||
this.reloadMessageList();
|
MessagelistUserStore.reload();
|
||||||
} else if (getFolderInboxName() === folderFromCache.fullName) {
|
} else if (getFolderInboxName() === folderFromCache.fullName) {
|
||||||
Remote.messageList(null, {Folder: getFolderInboxName()}, true);
|
Remote.messageList(null, {Folder: getFolderInboxName()}, true);
|
||||||
}
|
}
|
||||||
|
@ -421,126 +258,6 @@ class AppUser extends AbstractApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean=} boot = false
|
|
||||||
*/
|
|
||||||
folderInformationMultiply(boot = false) {
|
|
||||||
const folders = FolderUserStore.getNextFolderNames(refreshFolders);
|
|
||||||
if (arrayLength(folders)) {
|
|
||||||
Remote.request('FolderInformationMultiply', (iError, oData) => {
|
|
||||||
if (!iError && arrayLength(oData.Result)) {
|
|
||||||
const utc = Date.now();
|
|
||||||
oData.Result.forEach(item => {
|
|
||||||
const hash = getFolderHash(item.Folder),
|
|
||||||
folder = getFolderFromCacheList(item.Folder);
|
|
||||||
|
|
||||||
if (folder) {
|
|
||||||
folder.expires = utc;
|
|
||||||
|
|
||||||
setFolderHash(item.Folder, item.Hash);
|
|
||||||
|
|
||||||
folder.messageCountAll(item.MessageCount);
|
|
||||||
|
|
||||||
let unreadCountChange = folder.messageCountUnread() !== item.MessageUnseenCount;
|
|
||||||
|
|
||||||
folder.messageCountUnread(item.MessageUnseenCount);
|
|
||||||
|
|
||||||
if (unreadCountChange) {
|
|
||||||
MessageFlagsCache.clearFolder(folder.fullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hash || item.Hash !== hash) {
|
|
||||||
if (folder.fullName === FolderUserStore.currentFolderFullName()) {
|
|
||||||
this.reloadMessageList();
|
|
||||||
}
|
|
||||||
} else if (unreadCountChange
|
|
||||||
&& folder.fullName === FolderUserStore.currentFolderFullName()
|
|
||||||
&& MessageUserStore.list.length) {
|
|
||||||
this.folderInformation(folder.fullName, MessageUserStore.list());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (boot) {
|
|
||||||
setTimeout(() => this.folderInformationMultiply(true), 2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
Folders: folders
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} sFolderFullName
|
|
||||||
* @param {number} iSetAction
|
|
||||||
* @param {Array=} messages = null
|
|
||||||
*/
|
|
||||||
messageListAction(sFolderFullName, iSetAction, messages) {
|
|
||||||
messages = messages || MessageUserStore.listChecked();
|
|
||||||
|
|
||||||
let folder = null,
|
|
||||||
alreadyUnread = 0,
|
|
||||||
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null)
|
|
||||||
.validUnique(),
|
|
||||||
length = rootUids.length;
|
|
||||||
|
|
||||||
if (sFolderFullName && length) {
|
|
||||||
switch (iSetAction) {
|
|
||||||
case MessageSetAction.SetSeen:
|
|
||||||
length = 0;
|
|
||||||
// fallthrough is intentionally
|
|
||||||
case MessageSetAction.UnsetSeen:
|
|
||||||
rootUids.forEach(sSubUid =>
|
|
||||||
alreadyUnread += MessageFlagsCache.storeBySetAction(sFolderFullName, sSubUid, iSetAction)
|
|
||||||
);
|
|
||||||
|
|
||||||
folder = getFolderFromCacheList(sFolderFullName);
|
|
||||||
if (folder) {
|
|
||||||
folder.messageCountUnread(folder.messageCountUnread() - alreadyUnread + length);
|
|
||||||
}
|
|
||||||
|
|
||||||
Remote.request('MessageSetSeen', null, {
|
|
||||||
Folder: sFolderFullName,
|
|
||||||
Uids: rootUids.join(','),
|
|
||||||
SetAction: iSetAction == MessageSetAction.SetSeen ? 1 : 0
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MessageSetAction.SetFlag:
|
|
||||||
case MessageSetAction.UnsetFlag:
|
|
||||||
rootUids.forEach(sSubUid =>
|
|
||||||
MessageFlagsCache.storeBySetAction(sFolderFullName, sSubUid, iSetAction)
|
|
||||||
);
|
|
||||||
Remote.request('MessageSetFlagged', null, {
|
|
||||||
Folder: sFolderFullName,
|
|
||||||
Uids: rootUids.join(','),
|
|
||||||
SetAction: iSetAction == MessageSetAction.SetFlag ? 1 : 0
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
// no default
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} query
|
|
||||||
* @param {Function} autocompleteCallback
|
|
||||||
*/
|
|
||||||
getAutocomplete(query, autocompleteCallback) {
|
|
||||||
Remote.suggestions((iError, data) => {
|
|
||||||
if (!iError && isArray(data.Result)) {
|
|
||||||
autocompleteCallback(
|
|
||||||
data.Result.map(item => (item && item[0] ? new EmailModel(item[0], item[1]) : null)).filter(v => v)
|
|
||||||
);
|
|
||||||
} else if (Notification.RequestAborted !== iError) {
|
|
||||||
autocompleteCallback([]);
|
|
||||||
}
|
|
||||||
}, query);
|
|
||||||
}
|
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
Remote.request('Logout', () => rl.logoutReload());
|
Remote.request('Logout', () => rl.logoutReload());
|
||||||
}
|
}
|
||||||
|
@ -569,7 +286,7 @@ class AppUser extends AbstractApp {
|
||||||
SettingsUserStore.init();
|
SettingsUserStore.init();
|
||||||
ContactUserStore.init();
|
ContactUserStore.init();
|
||||||
|
|
||||||
Remote.foldersReload(value => {
|
loadFolders(value => {
|
||||||
try {
|
try {
|
||||||
if (value) {
|
if (value) {
|
||||||
startScreens([
|
startScreens([
|
||||||
|
@ -584,8 +301,8 @@ class AppUser extends AbstractApp {
|
||||||
if (iF !== cF) {
|
if (iF !== cF) {
|
||||||
this.folderInformation(cF);
|
this.folderInformation(cF);
|
||||||
}
|
}
|
||||||
this.folderInformationMultiply();
|
folderInformationMultiply();
|
||||||
}, refreshFolders);
|
}, refreshFoldersInterval);
|
||||||
|
|
||||||
ContactUserStore.init();
|
ContactUserStore.init();
|
||||||
|
|
||||||
|
@ -596,7 +313,7 @@ class AppUser extends AbstractApp {
|
||||||
if (getFolderInboxName() !== cF) {
|
if (getFolderInboxName() !== cF) {
|
||||||
this.folderInformation(cF);
|
this.folderInformation(cF);
|
||||||
}
|
}
|
||||||
FolderUserStore.hasCapability('LIST-STATUS') || this.folderInformationMultiply(true);
|
FolderUserStore.hasCapability('LIST-STATUS') || folderInformationMultiply(true);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
setTimeout(() => Remote.request('AppDelayStart'), 35000);
|
setTimeout(() => Remote.request('AppDelayStart'), 35000);
|
||||||
|
@ -639,7 +356,7 @@ class AppUser extends AbstractApp {
|
||||||
}
|
}
|
||||||
}, 1);
|
}, 1);
|
||||||
|
|
||||||
setInterval(this.reloadTime(), 60000);
|
setInterval(reloadTime(), 60000);
|
||||||
|
|
||||||
PgpUserStore.init();
|
PgpUserStore.init();
|
||||||
} else {
|
} else {
|
||||||
|
@ -655,13 +372,6 @@ class AppUser extends AbstractApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadTime()
|
|
||||||
{
|
|
||||||
setTimeout(() =>
|
|
||||||
doc.querySelectorAll('time').forEach(element => timeToNode(element))
|
|
||||||
, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
showMessageComposer(params = [])
|
showMessageComposer(params = [])
|
||||||
{
|
{
|
||||||
showScreenPopup(ComposePopupView, params);
|
showScreenPopup(ComposePopupView, params);
|
||||||
|
|
221
dev/Common/Folders.js
Normal file
221
dev/Common/Folders.js
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
import { isArray, arrayLength } from 'Common/Utils';
|
||||||
|
import {
|
||||||
|
MessageFlagsCache,
|
||||||
|
setFolderHash,
|
||||||
|
getFolderHash,
|
||||||
|
getFolderInboxName,
|
||||||
|
getFolderFromCacheList
|
||||||
|
} from 'Common/Cache';
|
||||||
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
import { getNotification } from 'Common/Translator';
|
||||||
|
|
||||||
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
|
export const
|
||||||
|
|
||||||
|
sortFolders = folders => {
|
||||||
|
try {
|
||||||
|
let collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
|
||||||
|
folders.sort((a, b) =>
|
||||||
|
a.isInbox() ? -1 : (b.isInbox() ? 1 : collator.compare(a.fullName, b.fullName))
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array=} aDisabled
|
||||||
|
* @param {Array=} aHeaderLines
|
||||||
|
* @param {Function=} fDisableCallback
|
||||||
|
* @param {Function=} fRenameCallback
|
||||||
|
* @param {boolean=} bNoSelectSelectable Used in FolderCreatePopupView
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
folderListOptionsBuilder = (
|
||||||
|
aDisabled,
|
||||||
|
aHeaderLines,
|
||||||
|
fRenameCallback,
|
||||||
|
fDisableCallback,
|
||||||
|
bNoSelectSelectable,
|
||||||
|
aList = FolderUserStore.folderList()
|
||||||
|
) => {
|
||||||
|
const
|
||||||
|
aResult = [],
|
||||||
|
sDeepPrefix = '\u00A0\u00A0\u00A0',
|
||||||
|
// FolderSystemPopupView should always be true
|
||||||
|
showUnsubscribed = fRenameCallback ? !SettingsUserStore.hideUnsubscribed() : true,
|
||||||
|
|
||||||
|
foldersWalk = folders => {
|
||||||
|
folders.forEach(oItem => {
|
||||||
|
if (showUnsubscribed || oItem.hasSubscriptions() || !oItem.exists) {
|
||||||
|
aResult.push({
|
||||||
|
id: oItem.fullName,
|
||||||
|
name:
|
||||||
|
sDeepPrefix.repeat(oItem.deep) +
|
||||||
|
fRenameCallback(oItem),
|
||||||
|
system: false,
|
||||||
|
disabled: !bNoSelectSelectable && (
|
||||||
|
!oItem.selectable() ||
|
||||||
|
aDisabled.includes(oItem.fullName) ||
|
||||||
|
fDisableCallback(oItem))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oItem.subFolders.length) {
|
||||||
|
foldersWalk(oItem.subFolders());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fDisableCallback = fDisableCallback || (() => false);
|
||||||
|
fRenameCallback = fRenameCallback || (oItem => oItem.name());
|
||||||
|
isArray(aDisabled) || (aDisabled = []);
|
||||||
|
|
||||||
|
isArray(aHeaderLines) && aHeaderLines.forEach(line =>
|
||||||
|
aResult.push({
|
||||||
|
id: line[0],
|
||||||
|
name: line[1],
|
||||||
|
system: false,
|
||||||
|
disabled: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
foldersWalk(aList);
|
||||||
|
|
||||||
|
return aResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Every 5 minutes
|
||||||
|
refreshFoldersInterval = 300000,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} boot = false
|
||||||
|
*/
|
||||||
|
folderInformationMultiply = (boot = false) => {
|
||||||
|
const folders = FolderUserStore.getNextFolderNames(refreshFoldersInterval);
|
||||||
|
if (arrayLength(folders)) {
|
||||||
|
Remote.request('FolderInformationMultiply', (iError, oData) => {
|
||||||
|
if (!iError && arrayLength(oData.Result)) {
|
||||||
|
const utc = Date.now();
|
||||||
|
oData.Result.forEach(item => {
|
||||||
|
const hash = getFolderHash(item.Folder),
|
||||||
|
folder = getFolderFromCacheList(item.Folder);
|
||||||
|
|
||||||
|
if (folder) {
|
||||||
|
folder.expires = utc;
|
||||||
|
|
||||||
|
setFolderHash(item.Folder, item.Hash);
|
||||||
|
|
||||||
|
folder.messageCountAll(item.MessageCount);
|
||||||
|
|
||||||
|
let unreadCountChange = folder.messageCountUnread() !== item.MessageUnseenCount;
|
||||||
|
|
||||||
|
folder.messageCountUnread(item.MessageUnseenCount);
|
||||||
|
|
||||||
|
if (unreadCountChange) {
|
||||||
|
MessageFlagsCache.clearFolder(folder.fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash || item.Hash !== hash) {
|
||||||
|
if (folder.fullName === FolderUserStore.currentFolderFullName()) {
|
||||||
|
MessagelistUserStore.reload();
|
||||||
|
}
|
||||||
|
} else if (unreadCountChange
|
||||||
|
&& folder.fullName === FolderUserStore.currentFolderFullName()
|
||||||
|
&& MessagelistUserStore.length) {
|
||||||
|
rl.app.folderInformation(folder.fullName, MessagelistUserStore());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (boot) {
|
||||||
|
setTimeout(() => folderInformationMultiply(true), 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
Folders: folders
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
moveOrDeleteResponseHelper = (iError, oData) => {
|
||||||
|
if (iError) {
|
||||||
|
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
||||||
|
alert(getNotification(iError));
|
||||||
|
} else if (FolderUserStore.currentFolder()) {
|
||||||
|
if (2 === arrayLength(oData.Result)) {
|
||||||
|
setFolderHash(oData.Result[0], oData.Result[1]);
|
||||||
|
} else {
|
||||||
|
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
||||||
|
}
|
||||||
|
MessagelistUserStore.reload(!MessagelistUserStore.length);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
messagesMoveHelper = (fromFolderFullName, toFolderFullName, uidsForMove) => {
|
||||||
|
const
|
||||||
|
sSpamFolder = FolderUserStore.spamFolder(),
|
||||||
|
isSpam = sSpamFolder === toFolderFullName,
|
||||||
|
isHam = !isSpam && sSpamFolder === fromFolderFullName && getFolderInboxName() === toFolderFullName;
|
||||||
|
|
||||||
|
Remote.request('MessageMove',
|
||||||
|
moveOrDeleteResponseHelper,
|
||||||
|
{
|
||||||
|
FromFolder: fromFolderFullName,
|
||||||
|
ToFolder: toFolderFullName,
|
||||||
|
Uids: uidsForMove.join(','),
|
||||||
|
MarkAsRead: (isSpam || FolderUserStore.trashFolder() === toFolderFullName) ? 1 : 0,
|
||||||
|
Learning: isSpam ? 'SPAM' : isHam ? 'HAM' : ''
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
'',
|
||||||
|
['MessageList']
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
messagesDeleteHelper = (sFromFolderFullName, aUidForRemove) => {
|
||||||
|
Remote.request('MessageDelete',
|
||||||
|
moveOrDeleteResponseHelper,
|
||||||
|
{
|
||||||
|
Folder: sFromFolderFullName,
|
||||||
|
Uids: aUidForRemove.join(',')
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
'',
|
||||||
|
['MessageList']
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFromFolderFullName
|
||||||
|
* @param {Array} aUidForMove
|
||||||
|
* @param {string} sToFolderFullName
|
||||||
|
* @param {boolean=} bCopy = false
|
||||||
|
*/
|
||||||
|
moveMessagesToFolder = (sFromFolderFullName, aUidForMove, sToFolderFullName, bCopy) => {
|
||||||
|
if (sFromFolderFullName !== sToFolderFullName && arrayLength(aUidForMove)) {
|
||||||
|
const oFromFolder = getFolderFromCacheList(sFromFolderFullName),
|
||||||
|
oToFolder = getFolderFromCacheList(sToFolderFullName);
|
||||||
|
|
||||||
|
if (oFromFolder && oToFolder) {
|
||||||
|
if (bCopy) {
|
||||||
|
Remote.request('MessageCopy', null, {
|
||||||
|
FromFolder: oFromFolder.fullName,
|
||||||
|
ToFolder: oToFolder.fullName,
|
||||||
|
Uids: aUidForMove.join(',')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
messagesMoveHelper(oFromFolder.fullName, oToFolder.fullName, aUidForMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.removeMessagesFromList(oFromFolder.fullName, aUidForMove, oToFolder.fullName, bCopy);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
|
@ -1,55 +0,0 @@
|
||||||
import { i18n } from 'Common/Translator';
|
|
||||||
|
|
||||||
export function timestampToString(timeStampInUTC, formatStr) {
|
|
||||||
const now = Date.now(),
|
|
||||||
time = 0 < timeStampInUTC ? Math.min(now, timeStampInUTC * 1000) : (0 === timeStampInUTC ? now : 0);
|
|
||||||
|
|
||||||
if (31536000000 < time) {
|
|
||||||
const m = new Date(time);
|
|
||||||
switch (formatStr) {
|
|
||||||
case 'FROMNOW':
|
|
||||||
return m.fromNow();
|
|
||||||
case 'SHORT': {
|
|
||||||
if (4 >= (now - time) / 3600000)
|
|
||||||
return m.fromNow();
|
|
||||||
const mt = m.getTime(), date = new Date,
|
|
||||||
dt = date.setHours(0,0,0,0);
|
|
||||||
if (mt > dt)
|
|
||||||
return i18n('MESSAGE_LIST/TODAY_AT', {TIME: m.format('LT')});
|
|
||||||
if (mt > dt - 86400000)
|
|
||||||
return i18n('MESSAGE_LIST/YESTERDAY_AT', {TIME: m.format('LT')});
|
|
||||||
if (date.getFullYear() === m.getFullYear())
|
|
||||||
return m.format('d M');
|
|
||||||
return m.format('LL');
|
|
||||||
}
|
|
||||||
case 'FULL':
|
|
||||||
return m.format('LLL');
|
|
||||||
default:
|
|
||||||
return m.format(formatStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function timeToNode(element, time) {
|
|
||||||
try {
|
|
||||||
if (time) {
|
|
||||||
element.dateTime = (new Date(time * 1000)).format('Y-m-d\\TH:i:s');
|
|
||||||
} else {
|
|
||||||
time = Date.parse(element.dateTime) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = element.dataset.momentFormat;
|
|
||||||
if (key) {
|
|
||||||
element.textContent = timestampToString(time, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((key = element.dataset.momentFormatTitle)) {
|
|
||||||
element.title = timestampToString(time, key);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// prevent knockout crashes
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -82,6 +82,64 @@ export const
|
||||||
element.querySelectorAll('[data-i18n]').forEach(item => i18nToNode(item))
|
element.querySelectorAll('[data-i18n]').forEach(item => i18nToNode(item))
|
||||||
, 1),
|
, 1),
|
||||||
|
|
||||||
|
timestampToString = (timeStampInUTC, formatStr) => {
|
||||||
|
const now = Date.now(),
|
||||||
|
time = 0 < timeStampInUTC ? Math.min(now, timeStampInUTC * 1000) : (0 === timeStampInUTC ? now : 0);
|
||||||
|
|
||||||
|
if (31536000000 < time) {
|
||||||
|
const m = new Date(time);
|
||||||
|
switch (formatStr) {
|
||||||
|
case 'FROMNOW':
|
||||||
|
return m.fromNow();
|
||||||
|
case 'SHORT': {
|
||||||
|
if (4 >= (now - time) / 3600000)
|
||||||
|
return m.fromNow();
|
||||||
|
const mt = m.getTime(), date = new Date,
|
||||||
|
dt = date.setHours(0,0,0,0);
|
||||||
|
if (mt > dt)
|
||||||
|
return i18n('MESSAGE_LIST/TODAY_AT', {TIME: m.format('LT')});
|
||||||
|
if (mt > dt - 86400000)
|
||||||
|
return i18n('MESSAGE_LIST/YESTERDAY_AT', {TIME: m.format('LT')});
|
||||||
|
if (date.getFullYear() === m.getFullYear())
|
||||||
|
return m.format('d M');
|
||||||
|
return m.format('LL');
|
||||||
|
}
|
||||||
|
case 'FULL':
|
||||||
|
return m.format('LLL');
|
||||||
|
default:
|
||||||
|
return m.format(formatStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
timeToNode = (element, time) => {
|
||||||
|
try {
|
||||||
|
if (time) {
|
||||||
|
element.dateTime = (new Date(time * 1000)).format('Y-m-d\\TH:i:s');
|
||||||
|
} else {
|
||||||
|
time = Date.parse(element.dateTime) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = element.dataset.momentFormat;
|
||||||
|
if (key) {
|
||||||
|
element.textContent = timestampToString(time, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((key = element.dataset.momentFormatTitle)) {
|
||||||
|
element.title = timestampToString(time, key);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// prevent knockout crashes
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reloadTime = () => setTimeout(() =>
|
||||||
|
doc.querySelectorAll('time').forEach(element => timeToNode(element))
|
||||||
|
, 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Function} startCallback
|
* @param {Function} startCallback
|
||||||
* @param {Function=} langCallback = null
|
* @param {Function=} langCallback = null
|
||||||
|
@ -129,7 +187,7 @@ export const
|
||||||
// reload the data
|
// reload the data
|
||||||
if (init()) {
|
if (init()) {
|
||||||
i18nToNodes(doc);
|
i18nToNodes(doc);
|
||||||
admin || rl.app.reloadTime();
|
admin || reloadTime();
|
||||||
trigger(!trigger());
|
trigger(!trigger());
|
||||||
}
|
}
|
||||||
script.remove();
|
script.remove();
|
||||||
|
|
|
@ -1,26 +1,18 @@
|
||||||
import { ComposeType/*, FolderType*/ } from 'Common/EnumsUser';
|
import { MessageFlagsCache, addRequestedMessage } from 'Common/Cache';
|
||||||
|
import { MessageSetAction, ComposeType/*, FolderType*/ } from 'Common/EnumsUser';
|
||||||
|
import { doc, createElement, elementById } from 'Common/Globals';
|
||||||
|
import { plainToHtml } from 'Common/Html';
|
||||||
|
import { getNotification } from 'Common/Translator';
|
||||||
import { EmailModel } from 'Model/Email';
|
import { EmailModel } from 'Model/Email';
|
||||||
import { isArray } from 'Common/Utils';
|
import { MessageModel } from 'Model/Message';
|
||||||
import { doc, createElement } from 'Common/Globals';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import * as Local from 'Storage/Client';
|
import * as Local from 'Storage/Client';
|
||||||
import { plainToHtml } from 'Common/Html';
|
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
export const
|
export const
|
||||||
|
|
||||||
sortFolders = folders => {
|
|
||||||
try {
|
|
||||||
let collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
|
|
||||||
folders.sort((a, b) =>
|
|
||||||
a.isInbox() ? -1 : (b.isInbox() ? 1 : collator.compare(a.fullName, b.fullName))
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} link
|
* @param {string} link
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
|
@ -39,69 +31,6 @@ download = (link, name = "") => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array=} aDisabled
|
|
||||||
* @param {Array=} aHeaderLines
|
|
||||||
* @param {Function=} fDisableCallback
|
|
||||||
* @param {Function=} fRenameCallback
|
|
||||||
* @param {boolean=} bNoSelectSelectable Used in FolderCreatePopupView
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
folderListOptionsBuilder = (
|
|
||||||
aDisabled,
|
|
||||||
aHeaderLines,
|
|
||||||
fRenameCallback,
|
|
||||||
fDisableCallback,
|
|
||||||
bNoSelectSelectable,
|
|
||||||
aList = FolderUserStore.folderList()
|
|
||||||
) => {
|
|
||||||
const
|
|
||||||
aResult = [],
|
|
||||||
sDeepPrefix = '\u00A0\u00A0\u00A0',
|
|
||||||
// FolderSystemPopupView should always be true
|
|
||||||
showUnsubscribed = fRenameCallback ? !SettingsUserStore.hideUnsubscribed() : true,
|
|
||||||
|
|
||||||
foldersWalk = folders => {
|
|
||||||
folders.forEach(oItem => {
|
|
||||||
if (showUnsubscribed || oItem.hasSubscriptions() || !oItem.exists) {
|
|
||||||
aResult.push({
|
|
||||||
id: oItem.fullName,
|
|
||||||
name:
|
|
||||||
sDeepPrefix.repeat(oItem.deep) +
|
|
||||||
fRenameCallback(oItem),
|
|
||||||
system: false,
|
|
||||||
disabled: !bNoSelectSelectable && (
|
|
||||||
!oItem.selectable() ||
|
|
||||||
aDisabled.includes(oItem.fullName) ||
|
|
||||||
fDisableCallback(oItem))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oItem.subFolders.length) {
|
|
||||||
foldersWalk(oItem.subFolders());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
fDisableCallback = fDisableCallback || (() => false);
|
|
||||||
fRenameCallback = fRenameCallback || (oItem => oItem.name());
|
|
||||||
isArray(aDisabled) || (aDisabled = []);
|
|
||||||
|
|
||||||
isArray(aHeaderLines) && aHeaderLines.forEach(line =>
|
|
||||||
aResult.push({
|
|
||||||
id: line[0],
|
|
||||||
name: line[1],
|
|
||||||
system: false,
|
|
||||||
disabled: false
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
foldersWalk(aList);
|
|
||||||
|
|
||||||
return aResult;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {function}
|
* @returns {function}
|
||||||
*/
|
*/
|
||||||
|
@ -334,4 +263,123 @@ setLayoutResizer = (source, target, sClientSideKeyName, mode) =>
|
||||||
} else {
|
} else {
|
||||||
source.observer && source.observer.disconnect();
|
source.observer && source.observer.disconnect();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
populateMessageBody = (oMessage, preload) => {
|
||||||
|
if (oMessage) {
|
||||||
|
preload || MessageUserStore.hideMessageBodies();
|
||||||
|
preload || MessageUserStore.loading(true);
|
||||||
|
rl.app.Remote.message((iError, oData/*, bCached*/) => {
|
||||||
|
if (iError) {
|
||||||
|
if (Notification.RequestAborted !== iError && !preload) {
|
||||||
|
MessageUserStore.message(null);
|
||||||
|
MessageUserStore.error(getNotification(iError));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oMessage = preload ? oMessage : null;
|
||||||
|
let
|
||||||
|
isNew = false,
|
||||||
|
json = oData && oData.Result,
|
||||||
|
message = oMessage || MessageUserStore.message();
|
||||||
|
|
||||||
|
if (
|
||||||
|
json &&
|
||||||
|
MessageModel.validJson(json) &&
|
||||||
|
message &&
|
||||||
|
message.folder === json.Folder
|
||||||
|
) {
|
||||||
|
const threads = message.threads(),
|
||||||
|
messagesDom = MessageUserStore.bodiesDom();
|
||||||
|
if (!oMessage && message.uid != json.Uid && threads.includes(json.Uid)) {
|
||||||
|
message = MessageModel.reviveFromJson(json);
|
||||||
|
if (message) {
|
||||||
|
message.threads(threads);
|
||||||
|
MessageFlagsCache.initMessage(message);
|
||||||
|
|
||||||
|
// Set clone
|
||||||
|
MessageUserStore.message(MessageModel.fromMessageListItem(message));
|
||||||
|
message = MessageUserStore.message();
|
||||||
|
|
||||||
|
isNew = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message && message.uid == json.Uid) {
|
||||||
|
oMessage || MessageUserStore.error('');
|
||||||
|
/*
|
||||||
|
if (bCached) {
|
||||||
|
delete json.Flags;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
isNew || message.revivePropertiesFromJson(json);
|
||||||
|
addRequestedMessage(message.folder, message.uid);
|
||||||
|
if (messagesDom) {
|
||||||
|
let id = 'rl-msg-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''),
|
||||||
|
body = elementById(id);
|
||||||
|
if (body) {
|
||||||
|
message.body = body;
|
||||||
|
message.isHtml(body.classList.contains('html'));
|
||||||
|
message.hasImages(body.rlHasImages);
|
||||||
|
} else {
|
||||||
|
body = Element.fromHTML('<div id="' + id + '" hidden="" class="b-text-part '
|
||||||
|
+ (message.pgpSigned() ? ' openpgp-signed' : '')
|
||||||
|
+ (message.pgpEncrypted() ? ' openpgp-encrypted' : '')
|
||||||
|
+ '">'
|
||||||
|
+ '</div>');
|
||||||
|
message.body = body;
|
||||||
|
if (!SettingsUserStore.viewHTML() || !message.viewHtml()) {
|
||||||
|
message.viewPlain();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageUserStore.purgeMessageBodyCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
messagesDom.append(body);
|
||||||
|
|
||||||
|
if (!oMessage) {
|
||||||
|
MessageUserStore.activeDom(message.body);
|
||||||
|
MessageUserStore.hideMessageBodies();
|
||||||
|
message.body.hidden = false;
|
||||||
|
}
|
||||||
|
oMessage && message.viewPopupMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlagsCache.initMessage(message);
|
||||||
|
if (message.isUnseen()) {
|
||||||
|
MessageUserStore.MessageSeenTimer = setTimeout(
|
||||||
|
() => MessagelistUserStore.setAction(message.folder, MessageSetAction.SetSeen, [message]),
|
||||||
|
SettingsUserStore.messageReadDelay() * 1000 // seconds
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message && isNew) {
|
||||||
|
let selectedMessage = MessagelistUserStore.selectedMessage();
|
||||||
|
if (
|
||||||
|
selectedMessage &&
|
||||||
|
(message.folder !== selectedMessage.folder || message.uid != selectedMessage.uid)
|
||||||
|
) {
|
||||||
|
MessagelistUserStore.selectedMessage(null);
|
||||||
|
if (1 === MessagelistUserStore.length) {
|
||||||
|
MessagelistUserStore.focusedMessage(null);
|
||||||
|
}
|
||||||
|
} else if (!selectedMessage) {
|
||||||
|
selectedMessage = MessagelistUserStore.find(
|
||||||
|
subMessage =>
|
||||||
|
subMessage &&
|
||||||
|
subMessage.folder === message.folder &&
|
||||||
|
subMessage.uid == message.uid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedMessage) {
|
||||||
|
MessagelistUserStore.selectedMessage(selectedMessage);
|
||||||
|
MessagelistUserStore.focusedMessage(selectedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preload || MessageUserStore.loading(false);
|
||||||
|
}, oMessage.folder, oMessage.uid);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
5
dev/External/User/ko.js
vendored
5
dev/External/User/ko.js
vendored
|
@ -1,11 +1,12 @@
|
||||||
import 'External/ko';
|
import 'External/ko';
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
import { HtmlEditor } from 'Common/Html';
|
import { HtmlEditor } from 'Common/Html';
|
||||||
import { timeToNode } from 'Common/Momentor';
|
import { timeToNode } from 'Common/Translator';
|
||||||
import { elementById } from 'Common/Globals';
|
import { elementById } from 'Common/Globals';
|
||||||
import { isArray } from 'Common/Utils';
|
import { isArray } from 'Common/Utils';
|
||||||
import { EmailAddressesComponent } from 'Component/EmailAddresses';
|
import { EmailAddressesComponent } from 'Component/EmailAddresses';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
import { moveMessagesToFolder } from 'Common/Folders';
|
||||||
|
|
||||||
const rlContentType = 'snappymail/action',
|
const rlContentType = 'snappymail/action',
|
||||||
|
|
||||||
|
@ -145,7 +146,7 @@ ko.bindingHandlers.dropmessages = {
|
||||||
if ('messages' === getDragAction(e) && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
if ('messages' === getDragAction(e) && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
||||||
let data = dragData.data;
|
let data = dragData.data;
|
||||||
if (folder && data && data.folder && isArray(data.uids)) {
|
if (folder && data && data.folder && isArray(data.uids)) {
|
||||||
rl.app.moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
|
moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
1
dev/External/ko.js
vendored
1
dev/External/ko.js
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
import ko from 'ko';
|
||||||
import { i18nToNodes } from 'Common/Translator';
|
import { i18nToNodes } from 'Common/Translator';
|
||||||
import { doc, createElement } from 'Common/Globals';
|
import { doc, createElement } from 'Common/Globals';
|
||||||
import { SaveSettingsStep } from 'Common/Enums';
|
import { SaveSettingsStep } from 'Common/Enums';
|
||||||
|
|
|
@ -10,12 +10,12 @@ import * as Local from 'Storage/Client';
|
||||||
|
|
||||||
import { AppUserStore } from 'Stores/User/App';
|
import { AppUserStore } from 'Stores/User/App';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
|
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import { sortFolders } from 'Common/UtilsUser';
|
import { sortFolders } from 'Common/Folders';
|
||||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||||
|
|
||||||
import { AbstractModel } from 'Knoin/AbstractModel';
|
import { AbstractModel } from 'Knoin/AbstractModel';
|
||||||
|
@ -24,6 +24,8 @@ import { koComputable } from 'External/ko';
|
||||||
|
|
||||||
//import { mailBox } from 'Common/Links';
|
//import { mailBox } from 'Common/Links';
|
||||||
|
|
||||||
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
const
|
const
|
||||||
isPosNumeric = value => null != value && /^[0-9]*$/.test(value.toString()),
|
isPosNumeric = value => null != value && /^[0-9]*$/.test(value.toString()),
|
||||||
|
|
||||||
|
@ -40,6 +42,51 @@ const
|
||||||
Spam: 0,
|
Spam: 0,
|
||||||
Trash: 0,
|
Trash: 0,
|
||||||
Archive: 0
|
Archive: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
kolabTypes = {
|
||||||
|
configuration: 'CONFIGURATION',
|
||||||
|
event: 'CALENDAR',
|
||||||
|
contact: 'CONTACTS',
|
||||||
|
task: 'TASKS',
|
||||||
|
note: 'NOTES',
|
||||||
|
file: 'FILES',
|
||||||
|
journal: 'JOURNAL'
|
||||||
|
},
|
||||||
|
|
||||||
|
getKolabFolderName = type => kolabTypes[type] ? 'Kolab ' + i18n('SETTINGS_FOLDERS/TYPE_' + kolabTypes[type]) : '',
|
||||||
|
|
||||||
|
getSystemFolderName = (type, def) => {
|
||||||
|
switch (type) {
|
||||||
|
case FolderType.Inbox:
|
||||||
|
case FolderType.Sent:
|
||||||
|
case FolderType.Drafts:
|
||||||
|
case FolderType.Trash:
|
||||||
|
case FolderType.Archive:
|
||||||
|
return i18n('FOLDER_LIST/' + getKeyByValue(FolderType, type).toUpperCase() + '_NAME');
|
||||||
|
case FolderType.Spam:
|
||||||
|
return i18n('GLOBAL/SPAM');
|
||||||
|
// no default
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
loadFolders = fCallback => {
|
||||||
|
// clearTimeout(this.foldersTimeout);
|
||||||
|
Remote.abort('Folders')
|
||||||
|
.post('Folders', FolderUserStore.foldersLoading)
|
||||||
|
.then(data => {
|
||||||
|
data = FolderCollectionModel.reviveFromJson(data.Result);
|
||||||
|
data && data.storeIt();
|
||||||
|
fCallback && fCallback(true);
|
||||||
|
// Repeat every 15 minutes?
|
||||||
|
// this.foldersTimeout = setTimeout(loadFolders, 900000);
|
||||||
|
})
|
||||||
|
.catch(() => fCallback && setTimeout(fCallback, 1, false));
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FolderCollectionModel extends AbstractCollectionModel
|
export class FolderCollectionModel extends AbstractCollectionModel
|
||||||
|
@ -163,36 +210,6 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getKolabFolderName(type)
|
|
||||||
{
|
|
||||||
const types = {
|
|
||||||
configuration: 'CONFIGURATION',
|
|
||||||
event: 'CALENDAR',
|
|
||||||
contact: 'CONTACTS',
|
|
||||||
task: 'TASKS',
|
|
||||||
note: 'NOTES',
|
|
||||||
file: 'FILES',
|
|
||||||
journal: 'JOURNAL'
|
|
||||||
};
|
|
||||||
return types[type] ? 'Kolab ' + i18n('SETTINGS_FOLDERS/TYPE_' + types[type]) : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSystemFolderName(type, def)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case FolderType.Inbox:
|
|
||||||
case FolderType.Sent:
|
|
||||||
case FolderType.Drafts:
|
|
||||||
case FolderType.Trash:
|
|
||||||
case FolderType.Archive:
|
|
||||||
return i18n('FOLDER_LIST/' + getKeyByValue(FolderType, type).toUpperCase() + '_NAME');
|
|
||||||
case FolderType.Spam:
|
|
||||||
return i18n('GLOBAL/SPAM');
|
|
||||||
// no default
|
|
||||||
}
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FolderModel extends AbstractModel {
|
export class FolderModel extends AbstractModel {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -296,7 +313,7 @@ export class FolderModel extends AbstractModel {
|
||||||
isInbox: () => FolderType.Inbox === folder.type(),
|
isInbox: () => FolderType.Inbox === folder.type(),
|
||||||
|
|
||||||
isFlagged: () => FolderUserStore.currentFolder() === folder
|
isFlagged: () => FolderUserStore.currentFolder() === folder
|
||||||
&& MessageUserStore.listSearch().includes('flagged'),
|
&& MessagelistUserStore.listSearch().includes('flagged'),
|
||||||
|
|
||||||
hasVisibleSubfolders: () => !!folder.subFolders().find(folder => folder.visible()),
|
hasVisibleSubfolders: () => !!folder.subFolders().find(folder => folder.visible()),
|
||||||
|
|
||||||
|
|
|
@ -532,52 +532,52 @@ export class MessageModel extends AbstractModel {
|
||||||
* @param {MessageModel} message
|
* @param {MessageModel} message
|
||||||
* @returns {MessageModel}
|
* @returns {MessageModel}
|
||||||
*/
|
*/
|
||||||
populateByMessageListItem(message) {
|
static fromMessageListItem(message) {
|
||||||
this.clear();
|
let self = new MessageModel();
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
this.folder = message.folder;
|
self.folder = message.folder;
|
||||||
this.uid = message.uid;
|
self.uid = message.uid;
|
||||||
this.hash = message.hash;
|
self.hash = message.hash;
|
||||||
this.requestHash = message.requestHash;
|
self.requestHash = message.requestHash;
|
||||||
this.subject(message.subject());
|
self.subject(message.subject());
|
||||||
this.plain(message.plain());
|
self.plain(message.plain());
|
||||||
this.html(message.html());
|
self.html(message.html());
|
||||||
|
|
||||||
this.size(message.size());
|
self.size(message.size());
|
||||||
this.spamScore(message.spamScore());
|
self.spamScore(message.spamScore());
|
||||||
this.spamResult(message.spamResult());
|
self.spamResult(message.spamResult());
|
||||||
this.isSpam(message.isSpam());
|
self.isSpam(message.isSpam());
|
||||||
this.hasVirus(message.hasVirus());
|
self.hasVirus(message.hasVirus());
|
||||||
this.dateTimeStampInUTC(message.dateTimeStampInUTC());
|
self.dateTimeStampInUTC(message.dateTimeStampInUTC());
|
||||||
this.priority(message.priority());
|
self.priority(message.priority());
|
||||||
|
|
||||||
this.hasExternals(message.hasExternals());
|
self.hasExternals(message.hasExternals());
|
||||||
|
|
||||||
this.emails = message.emails;
|
self.emails = message.emails;
|
||||||
|
|
||||||
this.from = message.from;
|
self.from = message.from;
|
||||||
this.to = message.to;
|
self.to = message.to;
|
||||||
this.cc = message.cc;
|
self.cc = message.cc;
|
||||||
this.bcc = message.bcc;
|
self.bcc = message.bcc;
|
||||||
this.replyTo = message.replyTo;
|
self.replyTo = message.replyTo;
|
||||||
this.deliveredTo = message.deliveredTo;
|
self.deliveredTo = message.deliveredTo;
|
||||||
this.unsubsribeLinks(message.unsubsribeLinks);
|
self.unsubsribeLinks(message.unsubsribeLinks);
|
||||||
|
|
||||||
this.flags(message.flags());
|
self.flags(message.flags());
|
||||||
|
|
||||||
this.priority(message.priority());
|
self.priority(message.priority());
|
||||||
|
|
||||||
this.selected(message.selected());
|
self.selected(message.selected());
|
||||||
this.checked(message.checked());
|
self.checked(message.checked());
|
||||||
this.attachments(message.attachments());
|
self.attachments(message.attachments());
|
||||||
|
|
||||||
this.threads(message.threads());
|
self.threads(message.threads());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.computeSenderEmail();
|
self.computeSenderEmail();
|
||||||
|
|
||||||
return this;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
showExternalImages() {
|
showExternalImages() {
|
||||||
|
|
|
@ -16,9 +16,7 @@ import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
|
||||||
import { AbstractFetchRemote } from 'Remote/AbstractFetch';
|
import { AbstractFetchRemote } from 'Remote/AbstractFetch';
|
||||||
|
|
||||||
import { FolderCollectionModel } from 'Model/FolderCollection';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
|
||||||
|
|
||||||
class RemoteUserFetch extends AbstractFetchRemote {
|
class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
|
|
||||||
|
@ -132,7 +130,7 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
UidNext: getFolderUidNext(folder) // Used to check for new messages
|
UidNext: getFolderUidNext(folder) // Used to check for new messages
|
||||||
});
|
});
|
||||||
} else if (SettingsUserStore.useThreads()) {
|
} else if (SettingsUserStore.useThreads()) {
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,23 +198,6 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?Function} fCallback
|
|
||||||
*/
|
|
||||||
foldersReload(fCallback) {
|
|
||||||
// clearTimeout(this.foldersTimeout);
|
|
||||||
this.abort('Folders')
|
|
||||||
.post('Folders', FolderUserStore.foldersLoading)
|
|
||||||
.then(data => {
|
|
||||||
data = FolderCollectionModel.reviveFromJson(data.Result);
|
|
||||||
data && data.storeIt();
|
|
||||||
fCallback && fCallback(true);
|
|
||||||
// Repeat every 15 minutes?
|
|
||||||
// this.foldersTimeout = setTimeout(() => this.foldersReload(), 900000);
|
|
||||||
})
|
|
||||||
.catch(() => fCallback && setTimeout(fCallback, 1, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
folderMove(sPrevFolderFullName, sNewFolderFullName, bSubscribe) {
|
folderMove(sPrevFolderFullName, sNewFolderFullName, bSubscribe) {
|
||||||
return this.post('FolderMove', FolderUserStore.foldersRenaming, {
|
return this.post('FolderMove', FolderUserStore.foldersRenaming, {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { AppUserStore } from 'Stores/User/App';
|
import { AppUserStore } from 'Stores/User/App';
|
||||||
import { AccountUserStore } from 'Stores/User/Account';
|
import { AccountUserStore } from 'Stores/User/Account';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
import { SystemDropDownUserView } from 'View/User/SystemDropDown';
|
import { SystemDropDownUserView } from 'View/User/SystemDropDown';
|
||||||
|
@ -70,11 +70,11 @@ export class MailBoxUserScreen extends AbstractScreen {
|
||||||
|
|
||||||
FolderUserStore.currentFolder(folder);
|
FolderUserStore.currentFolder(folder);
|
||||||
|
|
||||||
MessageUserStore.listPage(1 > page ? 1 : page);
|
MessagelistUserStore.page(1 > page ? 1 : page);
|
||||||
MessageUserStore.listSearch(search);
|
MessagelistUserStore.listSearch(search);
|
||||||
MessageUserStore.listThreadUid((folderHash === threadUid) ? 0 : pInt(threadUid));
|
MessagelistUserStore.threadUid((folderHash === threadUid) ? 0 : pInt(threadUid));
|
||||||
|
|
||||||
rl.app.reloadMessageList();
|
MessagelistUserStore.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { getNotification } from 'Common/Translator';
|
||||||
import { setFolder, getFolderFromCacheList, removeFolderFromCacheList } from 'Common/Cache';
|
import { setFolder, getFolderFromCacheList, removeFolderFromCacheList } from 'Common/Cache';
|
||||||
import { Capa } from 'Common/Enums';
|
import { Capa } from 'Common/Enums';
|
||||||
import { defaultOptionsAfterRender } from 'Common/Utils';
|
import { defaultOptionsAfterRender } from 'Common/Utils';
|
||||||
import { sortFolders } from 'Common/UtilsUser';
|
import { sortFolders } from 'Common/Folders';
|
||||||
import { initOnStartOrLangChange, i18n } from 'Common/Translator';
|
import { initOnStartOrLangChange, i18n } from 'Common/Translator';
|
||||||
|
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
@ -21,6 +21,7 @@ import { showScreenPopup } from 'Knoin/Knoin';
|
||||||
|
|
||||||
import { FolderCreatePopupView } from 'View/Popup/FolderCreate';
|
import { FolderCreatePopupView } from 'View/Popup/FolderCreate';
|
||||||
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
|
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
|
||||||
|
import { loadFolders } from 'Model/FolderCollection';
|
||||||
|
|
||||||
const folderForDeletion = ko.observable(null).askDeleteHelper();
|
const folderForDeletion = ko.observable(null).askDeleteHelper();
|
||||||
|
|
||||||
|
@ -79,8 +80,8 @@ export class FoldersUserSettings /*extends AbstractViewSettings*/ {
|
||||||
if (folder.subFolders.length) {
|
if (folder.subFolders.length) {
|
||||||
Remote.setTrigger(FolderUserStore.foldersLoading, true);
|
Remote.setTrigger(FolderUserStore.foldersLoading, true);
|
||||||
// clearTimeout(Remote.foldersTimeout);
|
// clearTimeout(Remote.foldersTimeout);
|
||||||
// Remote.foldersTimeout = setTimeout(() => Remote.foldersReload(), 500);
|
// Remote.foldersTimeout = setTimeout(loadFolders, 500);
|
||||||
setTimeout(() => Remote.foldersReload(), 500);
|
setTimeout(loadFolders, 500);
|
||||||
// TODO: rename all subfolders with folder.delimiter to prevent reload?
|
// TODO: rename all subfolders with folder.delimiter to prevent reload?
|
||||||
} else {
|
} else {
|
||||||
removeFolderFromCacheList(folder.fullName);
|
removeFolderFromCacheList(folder.fullName);
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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 { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ export class GeneralUserSettings /*extends AbstractViewSettings*/ {
|
||||||
showImages: value => Remote.saveSetting('ShowImages', value ? 1 : 0),
|
showImages: value => Remote.saveSetting('ShowImages', value ? 1 : 0),
|
||||||
|
|
||||||
removeColors: value => {
|
removeColors: value => {
|
||||||
let dom = MessageUserStore.messagesBodiesDom();
|
let dom = MessageUserStore.bodiesDom();
|
||||||
if (dom) {
|
if (dom) {
|
||||||
dom.innerHTML = '';
|
dom.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
@ -137,12 +138,12 @@ export class GeneralUserSettings /*extends AbstractViewSettings*/ {
|
||||||
replySameFolder: value => Remote.saveSetting('ReplySameFolder', value ? 1 : 0),
|
replySameFolder: value => Remote.saveSetting('ReplySameFolder', value ? 1 : 0),
|
||||||
|
|
||||||
useThreads: value => {
|
useThreads: value => {
|
||||||
MessageUserStore.list([]);
|
MessagelistUserStore([]);
|
||||||
Remote.saveSetting('UseThreads', value ? 1 : 0);
|
Remote.saveSetting('UseThreads', value ? 1 : 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
layout: value => {
|
layout: value => {
|
||||||
MessageUserStore.list([]);
|
MessagelistUserStore([]);
|
||||||
Remote.saveSetting('Layout', value, settingsSaveHelperSimpleFunction(this.layoutTrigger, this));
|
Remote.saveSetting('Layout', value, settingsSaveHelperSimpleFunction(this.layoutTrigger, this));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { forEachObjectEntry } from 'Common/Utils';
|
||||||
import { addObservablesTo, addSubscribablesTo, addComputablesTo } from 'External/ko';
|
import { addObservablesTo, addSubscribablesTo, addComputablesTo } from 'External/ko';
|
||||||
import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache';
|
import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache';
|
||||||
import { Settings } from 'Common/Globals';
|
import { Settings } from 'Common/Globals';
|
||||||
//import Remote from 'Remote/User/Fetch'; Circular dependency
|
//import Remote from 'Remote/User/Fetch'; // Circular dependency
|
||||||
|
|
||||||
export const FolderUserStore = new class {
|
export const FolderUserStore = new class {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
|
@ -1,137 +1,30 @@
|
||||||
import ko from 'ko';
|
import { Scope } from 'Common/Enums';
|
||||||
import { koComputable } from 'External/ko';
|
import { elementById } from 'Common/Globals';
|
||||||
|
import { addObservablesTo, addSubscribablesTo } from 'External/ko';
|
||||||
import { Scope, Notification } from 'Common/Enums';
|
|
||||||
import { MessageSetAction } from 'Common/EnumsUser';
|
|
||||||
import { $htmlCL, elementById } from 'Common/Globals';
|
|
||||||
import { arrayLength, pInt, pString } from 'Common/Utils';
|
|
||||||
import { addObservablesTo, addComputablesTo, addSubscribablesTo } from 'External/ko';
|
|
||||||
|
|
||||||
import {
|
|
||||||
getFolderInboxName,
|
|
||||||
addNewMessageCache,
|
|
||||||
setFolderUidNext,
|
|
||||||
getFolderFromCacheList,
|
|
||||||
setFolderHash,
|
|
||||||
MessageFlagsCache,
|
|
||||||
addRequestedMessage,
|
|
||||||
clearNewMessageCache
|
|
||||||
} from 'Common/Cache';
|
|
||||||
|
|
||||||
import { mailBox } from 'Common/Links';
|
|
||||||
import { i18n, getNotification } from 'Common/Translator';
|
|
||||||
|
|
||||||
import { EmailCollectionModel } from 'Model/EmailCollection';
|
|
||||||
import { MessageModel } from 'Model/Message';
|
|
||||||
import { MessageCollectionModel } from 'Model/MessageCollection';
|
|
||||||
|
|
||||||
import { AppUserStore } from 'Stores/User/App';
|
import { AppUserStore } from 'Stores/User/App';
|
||||||
import { AccountUserStore } from 'Stores/User/Account';
|
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { NotificationUserStore } from 'Stores/User/Notification';
|
|
||||||
|
|
||||||
//import Remote from 'Remote/User/Fetch'; Circular dependency
|
|
||||||
|
|
||||||
const
|
|
||||||
isChecked = item => item.checked();
|
|
||||||
|
|
||||||
let MessageSeenTimer;
|
|
||||||
|
|
||||||
export const MessageUserStore = new class {
|
export const MessageUserStore = new class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.staticMessage = new MessageModel();
|
|
||||||
|
|
||||||
this.list = ko.observableArray().extend({ debounce: 0 });
|
|
||||||
|
|
||||||
addObservablesTo(this, {
|
addObservablesTo(this, {
|
||||||
listCount: 0,
|
|
||||||
listSearch: '',
|
|
||||||
listThreadUid: 0,
|
|
||||||
listPage: 1,
|
|
||||||
listPageBeforeThread: 1,
|
|
||||||
listError: '',
|
|
||||||
|
|
||||||
listEndHash: '',
|
|
||||||
listEndThreadUid: 0,
|
|
||||||
|
|
||||||
listLoading: false,
|
|
||||||
// Happens when message(s) removed from list
|
|
||||||
listIsIncomplete: false,
|
|
||||||
|
|
||||||
selectorMessageSelected: null,
|
|
||||||
selectorMessageFocused: null,
|
|
||||||
|
|
||||||
// message viewer
|
// message viewer
|
||||||
message: null,
|
message: null,
|
||||||
messageViewTrigger: false,
|
error: '',
|
||||||
messageError: '',
|
loading: false,
|
||||||
messageLoading: false,
|
fullScreen: false,
|
||||||
messageFullScreenMode: false,
|
|
||||||
|
|
||||||
// Cache mail bodies
|
// Cache mail bodies
|
||||||
messagesBodiesDom: null,
|
bodiesDom: null,
|
||||||
messageActiveDom: null
|
activeDom: null
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listDisableAutoSelect = ko.observable(false).extend({ falseTimeout: 500 });
|
|
||||||
|
|
||||||
// Computed Observables
|
|
||||||
|
|
||||||
addComputablesTo(this, {
|
|
||||||
listIsLoading: () => {
|
|
||||||
const value = this.listLoading() | this.listIsIncomplete();
|
|
||||||
$htmlCL.toggle('list-loading', value);
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
|
|
||||||
listPageCount: () => Math.max(1, Math.ceil(this.listCount() / SettingsUserStore.messagesPerPage())),
|
|
||||||
|
|
||||||
mainMessageListSearch: {
|
|
||||||
read: this.listSearch,
|
|
||||||
write: value => rl.route.setHash(
|
|
||||||
mailBox(FolderUserStore.currentFolderFullNameHash(), 1, value.toString().trim(), this.listThreadUid())
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
isMessageSelected: () => null !== this.message(),
|
|
||||||
|
|
||||||
listCheckedOrSelected: () => {
|
|
||||||
const
|
|
||||||
selectedMessage = this.selectorMessageSelected(),
|
|
||||||
focusedMessage = this.selectorMessageFocused(),
|
|
||||||
checked = this.list.filter(item => isChecked(item) || item === selectedMessage);
|
|
||||||
return checked.length ? checked : (focusedMessage ? [focusedMessage] : []);
|
|
||||||
},
|
|
||||||
|
|
||||||
listCheckedOrSelectedUidsWithSubMails: () => {
|
|
||||||
let result = [];
|
|
||||||
this.listCheckedOrSelected().forEach(message => {
|
|
||||||
result.push(message.uid);
|
|
||||||
if (1 < message.threadsLen()) {
|
|
||||||
result = result.concat(message.threads()).unique();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.listChecked = koComputable(() => this.list.filter(isChecked))
|
|
||||||
.extend({ rateLimit: 0 });
|
|
||||||
|
|
||||||
this.hasCheckedMessages = koComputable(() => !!this.list.find(isChecked))
|
|
||||||
.extend({ rateLimit: 0 });
|
|
||||||
|
|
||||||
this.hasCheckedOrSelected = koComputable(() => !!(this.selectorMessageSelected()
|
|
||||||
|| this.selectorMessageFocused()
|
|
||||||
|| this.list.find(item => item.checked())))
|
|
||||||
.extend({ rateLimit: 50 });
|
|
||||||
|
|
||||||
// Subscribers
|
// Subscribers
|
||||||
|
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(this, {
|
||||||
message: message => {
|
message: message => {
|
||||||
clearTimeout(MessageSeenTimer);
|
clearTimeout(this.MessageSeenTimer);
|
||||||
|
elementById('rl-right').classList.toggle('message-selected', !!message);
|
||||||
if (message) {
|
if (message) {
|
||||||
if (!SettingsUserStore.usePreviewPane()) {
|
if (!SettingsUserStore.usePreviewPane()) {
|
||||||
AppUserStore.focusedState(Scope.MessageView);
|
AppUserStore.focusedState(Scope.MessageView);
|
||||||
|
@ -139,19 +32,17 @@ export const MessageUserStore = new class {
|
||||||
} else {
|
} else {
|
||||||
AppUserStore.focusedState(Scope.MessageList);
|
AppUserStore.focusedState(Scope.MessageList);
|
||||||
|
|
||||||
this.messageFullScreenMode(false);
|
this.fullScreen(false);
|
||||||
this.hideMessageBodies();
|
this.hideMessageBodies();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
isMessageSelected: value => elementById('rl-right').classList.toggle('message-selected', value)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.purgeMessageBodyCache = this.purgeMessageBodyCache.throttle(30000);
|
this.purgeMessageBodyCache = this.purgeMessageBodyCache.throttle(30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeMessageBodyCache() {
|
purgeMessageBodyCache() {
|
||||||
const messagesDom = this.messagesBodiesDom(),
|
const messagesDom = this.bodiesDom(),
|
||||||
children = messagesDom && messagesDom.children;
|
children = messagesDom && messagesDom.children;
|
||||||
if (children) {
|
if (children) {
|
||||||
while (15 < children.length) {
|
while (15 < children.length) {
|
||||||
|
@ -160,390 +51,8 @@ export const MessageUserStore = new class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initUidNextAndNewMessages(folder, uidNext, newMessages) {
|
|
||||||
if (getFolderInboxName() === folder && uidNext) {
|
|
||||||
if (arrayLength(newMessages)) {
|
|
||||||
newMessages.forEach(item => addNewMessageCache(folder, item.Uid));
|
|
||||||
|
|
||||||
NotificationUserStore.playSoundNotification();
|
|
||||||
|
|
||||||
const len = newMessages.length;
|
|
||||||
if (3 < len) {
|
|
||||||
NotificationUserStore.displayDesktopNotification(
|
|
||||||
AccountUserStore.email(),
|
|
||||||
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
|
|
||||||
COUNT: len
|
|
||||||
}),
|
|
||||||
{ Url: mailBox(newMessages[0].Folder) }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
newMessages.forEach(item => {
|
|
||||||
NotificationUserStore.displayDesktopNotification(
|
|
||||||
EmailCollectionModel.reviveFromJson(item.From).toString(),
|
|
||||||
item.Subject,
|
|
||||||
{ Folder: item.Folder, Uid: item.Uid }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFolderUidNext(folder, uidNext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hideMessageBodies() {
|
hideMessageBodies() {
|
||||||
const messagesDom = this.messagesBodiesDom();
|
const messagesDom = this.bodiesDom();
|
||||||
messagesDom && Array.from(messagesDom.children).forEach(el => el.hidden = true);
|
messagesDom && Array.from(messagesDom.children).forEach(el => el.hidden = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} fromFolderFullName
|
|
||||||
* @param {Array} uidForRemove
|
|
||||||
* @param {string=} toFolderFullName = ''
|
|
||||||
* @param {boolean=} copy = false
|
|
||||||
*/
|
|
||||||
removeMessagesFromList(fromFolderFullName, uidForRemove, toFolderFullName = '', copy = false) {
|
|
||||||
uidForRemove = uidForRemove.map(mValue => pInt(mValue));
|
|
||||||
|
|
||||||
let unseenCount = 0,
|
|
||||||
messageList = this.list,
|
|
||||||
currentMessage = this.message();
|
|
||||||
|
|
||||||
const trashFolder = FolderUserStore.trashFolder(),
|
|
||||||
spamFolder = FolderUserStore.spamFolder(),
|
|
||||||
fromFolder = getFolderFromCacheList(fromFolderFullName),
|
|
||||||
toFolder = toFolderFullName ? getFolderFromCacheList(toFolderFullName) : null,
|
|
||||||
messages =
|
|
||||||
FolderUserStore.currentFolderFullName() === fromFolderFullName
|
|
||||||
? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid)))
|
|
||||||
: [];
|
|
||||||
|
|
||||||
messages.forEach(item => {
|
|
||||||
if (item && item.isUnseen()) {
|
|
||||||
++unseenCount;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (fromFolder && !copy) {
|
|
||||||
fromFolder.messageCountAll(
|
|
||||||
0 <= fromFolder.messageCountAll() - uidForRemove.length ? fromFolder.messageCountAll() - uidForRemove.length : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (0 < unseenCount) {
|
|
||||||
fromFolder.messageCountUnread(
|
|
||||||
0 <= fromFolder.messageCountUnread() - unseenCount ? fromFolder.messageCountUnread() - unseenCount : 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toFolder) {
|
|
||||||
if (trashFolder === toFolder.fullName || spamFolder === toFolder.fullName) {
|
|
||||||
unseenCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
toFolder.messageCountAll(toFolder.messageCountAll() + uidForRemove.length);
|
|
||||||
if (0 < unseenCount) {
|
|
||||||
toFolder.messageCountUnread(toFolder.messageCountUnread() + unseenCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
toFolder.actionBlink(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (messages.length) {
|
|
||||||
if (copy) {
|
|
||||||
messages.forEach(item => item.checked(false));
|
|
||||||
} else {
|
|
||||||
this.listIsIncomplete(true);
|
|
||||||
|
|
||||||
messages.forEach(item => {
|
|
||||||
if (currentMessage && currentMessage.hash === item.hash) {
|
|
||||||
currentMessage = null;
|
|
||||||
this.message(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
item.deleted(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => messages.forEach(item => messageList.remove(item)), 350);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fromFolderFullName) {
|
|
||||||
setFolderHash(fromFolderFullName, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toFolderFullName) {
|
|
||||||
setFolderHash(toFolderFullName, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.listThreadUid()) {
|
|
||||||
if (
|
|
||||||
messageList.length &&
|
|
||||||
!!messageList.find(item => !!(item && item.deleted() && item.uid == this.listThreadUid()))
|
|
||||||
) {
|
|
||||||
const message = messageList.find(item => item && !item.deleted());
|
|
||||||
if (message && this.listThreadUid() != message.uid) {
|
|
||||||
this.listThreadUid(message.uid);
|
|
||||||
|
|
||||||
rl.route.setHash(
|
|
||||||
mailBox(
|
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
|
||||||
this.listPage(),
|
|
||||||
this.listSearch(),
|
|
||||||
this.listThreadUid()
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
} else if (!message) {
|
|
||||||
if (1 < this.listPage()) {
|
|
||||||
this.listPage(this.listPage() - 1);
|
|
||||||
|
|
||||||
rl.route.setHash(
|
|
||||||
mailBox(
|
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
|
||||||
this.listPage(),
|
|
||||||
this.listSearch(),
|
|
||||||
this.listThreadUid()
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.listThreadUid(0);
|
|
||||||
|
|
||||||
rl.route.setHash(
|
|
||||||
mailBox(
|
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
|
||||||
this.listPageBeforeThread(),
|
|
||||||
this.listSearch()
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setMessage(data, cached, oMessage) {
|
|
||||||
let isNew = false,
|
|
||||||
json = data && data.Result,
|
|
||||||
message = oMessage || this.message();
|
|
||||||
|
|
||||||
if (
|
|
||||||
json &&
|
|
||||||
MessageModel.validJson(json) &&
|
|
||||||
message &&
|
|
||||||
message.folder === json.Folder
|
|
||||||
) {
|
|
||||||
const threads = message.threads(),
|
|
||||||
messagesDom = this.messagesBodiesDom();
|
|
||||||
if (!oMessage && message.uid != json.Uid && threads.includes(json.Uid)) {
|
|
||||||
message = MessageModel.reviveFromJson(json);
|
|
||||||
if (message) {
|
|
||||||
message.threads(threads);
|
|
||||||
MessageFlagsCache.initMessage(message);
|
|
||||||
|
|
||||||
this.message(this.staticMessage.populateByMessageListItem(message));
|
|
||||||
message = this.message();
|
|
||||||
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message && message.uid == json.Uid) {
|
|
||||||
oMessage || this.messageError('');
|
|
||||||
/*
|
|
||||||
if (cached) {
|
|
||||||
delete json.Flags;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
isNew || message.revivePropertiesFromJson(json);
|
|
||||||
addRequestedMessage(message.folder, message.uid);
|
|
||||||
if (messagesDom) {
|
|
||||||
let id = 'rl-msg-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''),
|
|
||||||
body = elementById(id);
|
|
||||||
if (body) {
|
|
||||||
message.body = body;
|
|
||||||
message.isHtml(body.classList.contains('html'));
|
|
||||||
message.hasImages(body.rlHasImages);
|
|
||||||
} else {
|
|
||||||
body = Element.fromHTML('<div id="' + id + '" hidden="" class="b-text-part '
|
|
||||||
+ (message.pgpSigned() ? ' openpgp-signed' : '')
|
|
||||||
+ (message.pgpEncrypted() ? ' openpgp-encrypted' : '')
|
|
||||||
+ '">'
|
|
||||||
+ '</div>');
|
|
||||||
message.body = body;
|
|
||||||
if (!SettingsUserStore.viewHTML() || !message.viewHtml()) {
|
|
||||||
message.viewPlain();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.purgeMessageBodyCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
messagesDom.append(body);
|
|
||||||
|
|
||||||
oMessage || this.messageActiveDom(message.body);
|
|
||||||
|
|
||||||
oMessage || this.hideMessageBodies();
|
|
||||||
|
|
||||||
oMessage || (message.body.hidden = false);
|
|
||||||
oMessage && message.viewPopupMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageFlagsCache.initMessage(message);
|
|
||||||
if (message.isUnseen()) {
|
|
||||||
MessageSeenTimer = setTimeout(
|
|
||||||
() => rl.app.messageListAction(message.folder, MessageSetAction.SetSeen, [message]),
|
|
||||||
SettingsUserStore.messageReadDelay() * 1000 // seconds
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message && isNew) {
|
|
||||||
let selectedMessage = this.selectorMessageSelected();
|
|
||||||
if (
|
|
||||||
selectedMessage &&
|
|
||||||
(message.folder !== selectedMessage.folder || message.uid != selectedMessage.uid)
|
|
||||||
) {
|
|
||||||
this.selectorMessageSelected(null);
|
|
||||||
if (1 === this.list.length) {
|
|
||||||
this.selectorMessageFocused(null);
|
|
||||||
}
|
|
||||||
} else if (!selectedMessage) {
|
|
||||||
selectedMessage = this.list.find(
|
|
||||||
subMessage =>
|
|
||||||
subMessage &&
|
|
||||||
subMessage.folder === message.folder &&
|
|
||||||
subMessage.uid == message.uid
|
|
||||||
);
|
|
||||||
|
|
||||||
if (selectedMessage) {
|
|
||||||
this.selectorMessageSelected(selectedMessage);
|
|
||||||
this.selectorMessageFocused(selectedMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectMessage(oMessage) {
|
|
||||||
if (oMessage) {
|
|
||||||
this.message(this.staticMessage.populateByMessageListItem(oMessage));
|
|
||||||
this.populateMessageBody(this.message());
|
|
||||||
} else {
|
|
||||||
this.message(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectMessageByFolderAndUid(sFolder, iUid) {
|
|
||||||
if (sFolder && iUid) {
|
|
||||||
this.message(this.staticMessage.populateByMessageListItem(null));
|
|
||||||
this.message().folder = sFolder;
|
|
||||||
this.message().uid = iUid;
|
|
||||||
|
|
||||||
this.populateMessageBody(this.message());
|
|
||||||
} else {
|
|
||||||
this.message(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
populateMessageBody(oMessage, preload) {
|
|
||||||
if (oMessage) {
|
|
||||||
preload || this.hideMessageBodies();
|
|
||||||
preload || this.messageLoading(true);
|
|
||||||
rl.app.Remote.message((iError, oData, bCached) => {
|
|
||||||
if (iError) {
|
|
||||||
if (Notification.RequestAborted !== iError && !preload) {
|
|
||||||
this.message(null);
|
|
||||||
this.messageError(getNotification(iError));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setMessage(oData, bCached, preload ? oMessage : null);
|
|
||||||
}
|
|
||||||
preload || this.messageLoading(false);
|
|
||||||
}, oMessage.folder, oMessage.uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array} list
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
calculateMessageListHash(list) {
|
|
||||||
return list.map(message => message.hash + '_' + message.threadsLen() + '_' + message.flagHash()).join(
|
|
||||||
'|'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadFlagsAndCachedMessage() {
|
|
||||||
this.list.forEach(message => MessageFlagsCache.initMessage(message));
|
|
||||||
MessageFlagsCache.initMessage(this.message());
|
|
||||||
this.messageViewTrigger(!this.messageViewTrigger());
|
|
||||||
}
|
|
||||||
|
|
||||||
setMessageList(data, cached) {
|
|
||||||
const collection = MessageCollectionModel.reviveFromJson(data.Result, cached);
|
|
||||||
if (collection) {
|
|
||||||
let unreadCountChange = false;
|
|
||||||
|
|
||||||
const
|
|
||||||
folder = getFolderFromCacheList(collection.Folder);
|
|
||||||
|
|
||||||
if (folder && !cached) {
|
|
||||||
folder.expires = Date.now();
|
|
||||||
|
|
||||||
setFolderHash(collection.Folder, collection.FolderHash);
|
|
||||||
|
|
||||||
if (null != collection.MessageCount) {
|
|
||||||
folder.messageCountAll(collection.MessageCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null != collection.MessageUnseenCount) {
|
|
||||||
if (pInt(folder.messageCountUnread()) !== pInt(collection.MessageUnseenCount)) {
|
|
||||||
unreadCountChange = true;
|
|
||||||
MessageFlagsCache.clearFolder(folder.fullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
folder.messageCountUnread(collection.MessageUnseenCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initUidNextAndNewMessages(folder.fullName, collection.UidNext, collection.NewMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.listCount(collection.MessageResultCount);
|
|
||||||
this.listSearch(pString(collection.Search));
|
|
||||||
this.listPage(Math.ceil(collection.Offset / SettingsUserStore.messagesPerPage() + 1));
|
|
||||||
this.listThreadUid(collection.ThreadUid);
|
|
||||||
|
|
||||||
this.listEndHash(
|
|
||||||
collection.Folder +
|
|
||||||
'|' + collection.Search +
|
|
||||||
'|' + this.listThreadUid() +
|
|
||||||
'|' + this.listPage()
|
|
||||||
);
|
|
||||||
this.listEndThreadUid(collection.ThreadUid);
|
|
||||||
const message = this.message();
|
|
||||||
if (message && collection.Folder !== message.folder) {
|
|
||||||
this.message(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.listDisableAutoSelect(true);
|
|
||||||
|
|
||||||
this.list(collection);
|
|
||||||
this.listIsIncomplete(false);
|
|
||||||
|
|
||||||
clearNewMessageCache();
|
|
||||||
|
|
||||||
if (folder && (cached || unreadCountChange || SettingsUserStore.useThreads())) {
|
|
||||||
rl.app.folderInformation(folder.fullName, collection);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.listCount(0);
|
|
||||||
this.list([]);
|
|
||||||
this.listError(getNotification(Notification.CantGetMessageList));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
435
dev/Stores/User/Messagelist.js
Normal file
435
dev/Stores/User/Messagelist.js
Normal file
|
@ -0,0 +1,435 @@
|
||||||
|
import { koComputable } from 'External/ko';
|
||||||
|
|
||||||
|
import { MessageSetAction } from 'Common/EnumsUser';
|
||||||
|
import { $htmlCL } from 'Common/Globals';
|
||||||
|
import { arrayLength, pInt, pString } from 'Common/Utils';
|
||||||
|
import { addObservablesTo, addComputablesTo } from 'External/ko';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getFolderInboxName,
|
||||||
|
addNewMessageCache,
|
||||||
|
setFolderUidNext,
|
||||||
|
getFolderFromCacheList,
|
||||||
|
setFolderHash,
|
||||||
|
MessageFlagsCache,
|
||||||
|
clearNewMessageCache
|
||||||
|
} from 'Common/Cache';
|
||||||
|
|
||||||
|
import { mailBox } from 'Common/Links';
|
||||||
|
import { i18n, getNotification } from 'Common/Translator';
|
||||||
|
|
||||||
|
import { EmailCollectionModel } from 'Model/EmailCollection';
|
||||||
|
import { MessageCollectionModel } from 'Model/MessageCollection';
|
||||||
|
|
||||||
|
import { AccountUserStore } from 'Stores/User/Account';
|
||||||
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { NotificationUserStore } from 'Stores/User/Notification';
|
||||||
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
|
|
||||||
|
//import Remote from 'Remote/User/Fetch'; // Circular dependency
|
||||||
|
|
||||||
|
const
|
||||||
|
isChecked = item => item.checked();
|
||||||
|
|
||||||
|
export const MessagelistUserStore = ko.observableArray().extend({ debounce: 0 });
|
||||||
|
|
||||||
|
addObservablesTo(MessagelistUserStore, {
|
||||||
|
count: 0,
|
||||||
|
listSearch: '',
|
||||||
|
threadUid: 0,
|
||||||
|
page: 1,
|
||||||
|
pageBeforeThread: 1,
|
||||||
|
error: '',
|
||||||
|
|
||||||
|
endHash: '',
|
||||||
|
endThreadUid: 0,
|
||||||
|
|
||||||
|
loading: false,
|
||||||
|
// Happens when message(s) removed from list
|
||||||
|
isIncomplete: false,
|
||||||
|
|
||||||
|
selectedMessage: null,
|
||||||
|
focusedMessage: null
|
||||||
|
});
|
||||||
|
|
||||||
|
MessagelistUserStore.disableAutoSelect = ko.observable(false).extend({ falseTimeout: 500 });
|
||||||
|
|
||||||
|
// Computed Observables
|
||||||
|
|
||||||
|
addComputablesTo(MessagelistUserStore, {
|
||||||
|
isLoading: () => {
|
||||||
|
const value = MessagelistUserStore.loading() | MessagelistUserStore.isIncomplete();
|
||||||
|
$htmlCL.toggle('list-loading', value);
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
pageCount: () => Math.max(1, Math.ceil(MessagelistUserStore.count() / SettingsUserStore.messagesPerPage())),
|
||||||
|
|
||||||
|
mainSearch: {
|
||||||
|
read: MessagelistUserStore.listSearch,
|
||||||
|
write: value => rl.route.setHash(
|
||||||
|
mailBox(FolderUserStore.currentFolderFullNameHash(), 1,
|
||||||
|
value.toString().trim(), MessagelistUserStore.threadUid())
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
listCheckedOrSelected: () => {
|
||||||
|
const
|
||||||
|
selectedMessage = MessagelistUserStore.selectedMessage(),
|
||||||
|
focusedMessage = MessagelistUserStore.focusedMessage(),
|
||||||
|
checked = MessagelistUserStore.filter(item => isChecked(item) || item === selectedMessage);
|
||||||
|
return checked.length ? checked : (focusedMessage ? [focusedMessage] : []);
|
||||||
|
},
|
||||||
|
|
||||||
|
listCheckedOrSelectedUidsWithSubMails: () => {
|
||||||
|
let result = [];
|
||||||
|
MessagelistUserStore.listCheckedOrSelected().forEach(message => {
|
||||||
|
result.push(message.uid);
|
||||||
|
if (1 < message.threadsLen()) {
|
||||||
|
result = result.concat(message.threads()).unique();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
MessagelistUserStore.listChecked = koComputable(
|
||||||
|
() => MessagelistUserStore.filter(isChecked)).extend({ rateLimit: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
MessagelistUserStore.hasCheckedMessages = koComputable(
|
||||||
|
() => !!MessagelistUserStore.find(isChecked)
|
||||||
|
).extend({ rateLimit: 0 });
|
||||||
|
|
||||||
|
MessagelistUserStore.hasCheckedOrSelected = koComputable(() =>
|
||||||
|
!!(MessagelistUserStore.selectedMessage()
|
||||||
|
|| MessagelistUserStore.focusedMessage()
|
||||||
|
|| MessagelistUserStore.find(item => item.checked()))
|
||||||
|
).extend({ rateLimit: 50 });
|
||||||
|
|
||||||
|
MessagelistUserStore.initUidNextAndNewMessages = (folder, uidNext, newMessages) => {
|
||||||
|
if (getFolderInboxName() === folder && uidNext) {
|
||||||
|
if (arrayLength(newMessages)) {
|
||||||
|
newMessages.forEach(item => addNewMessageCache(folder, item.Uid));
|
||||||
|
|
||||||
|
NotificationUserStore.playSoundNotification();
|
||||||
|
|
||||||
|
const len = newMessages.length;
|
||||||
|
if (3 < len) {
|
||||||
|
NotificationUserStore.displayDesktopNotification(
|
||||||
|
AccountUserStore.email(),
|
||||||
|
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
|
||||||
|
COUNT: len
|
||||||
|
}),
|
||||||
|
{ Url: mailBox(newMessages[0].Folder) }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
newMessages.forEach(item => {
|
||||||
|
NotificationUserStore.displayDesktopNotification(
|
||||||
|
EmailCollectionModel.reviveFromJson(item.From).toString(),
|
||||||
|
item.Subject,
|
||||||
|
{ Folder: item.Folder, Uid: item.Uid }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFolderUidNext(folder, uidNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bDropPagePosition = false
|
||||||
|
* @param {boolean=} bDropCurrenFolderCache = false
|
||||||
|
*/
|
||||||
|
MessagelistUserStore.reload = (bDropPagePosition = false, bDropCurrenFolderCache = false) => {
|
||||||
|
let iOffset = (MessagelistUserStore.page() - 1) * SettingsUserStore.messagesPerPage();
|
||||||
|
|
||||||
|
if (bDropCurrenFolderCache) {
|
||||||
|
setFolderHash(FolderUserStore.currentFolderFullName(), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bDropPagePosition) {
|
||||||
|
MessagelistUserStore.page(1);
|
||||||
|
MessagelistUserStore.pageBeforeThread(1);
|
||||||
|
iOffset = 0;
|
||||||
|
|
||||||
|
rl.route.setHash(
|
||||||
|
mailBox(
|
||||||
|
FolderUserStore.currentFolderFullNameHash(),
|
||||||
|
MessagelistUserStore.page(),
|
||||||
|
MessagelistUserStore.listSearch(),
|
||||||
|
MessagelistUserStore.threadUid()
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.loading(true);
|
||||||
|
MessagelistUserStore.error('');
|
||||||
|
rl.app.Remote.messageList(
|
||||||
|
(iError, oData, bCached) => {
|
||||||
|
if (iError) {
|
||||||
|
if (Notification.RequestAborted !== iError) {
|
||||||
|
MessagelistUserStore([]);
|
||||||
|
MessagelistUserStore.error(getNotification(iError));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const collection = MessageCollectionModel.reviveFromJson(oData.Result, bCached);
|
||||||
|
if (collection) {
|
||||||
|
let unreadCountChange = false;
|
||||||
|
|
||||||
|
const
|
||||||
|
folder = getFolderFromCacheList(collection.Folder);
|
||||||
|
|
||||||
|
if (folder && !bCached) {
|
||||||
|
folder.expires = Date.now();
|
||||||
|
|
||||||
|
setFolderHash(collection.Folder, collection.FolderHash);
|
||||||
|
|
||||||
|
if (null != collection.MessageCount) {
|
||||||
|
folder.messageCountAll(collection.MessageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != collection.MessageUnseenCount) {
|
||||||
|
if (pInt(folder.messageCountUnread()) !== pInt(collection.MessageUnseenCount)) {
|
||||||
|
unreadCountChange = true;
|
||||||
|
MessageFlagsCache.clearFolder(folder.fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.messageCountUnread(collection.MessageUnseenCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.initUidNextAndNewMessages(folder.fullName, collection.UidNext, collection.NewMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.count(collection.MessageResultCount);
|
||||||
|
MessagelistUserStore.listSearch(pString(collection.Search));
|
||||||
|
MessagelistUserStore.page(Math.ceil(collection.Offset / SettingsUserStore.messagesPerPage() + 1));
|
||||||
|
MessagelistUserStore.threadUid(collection.ThreadUid);
|
||||||
|
|
||||||
|
MessagelistUserStore.endHash(
|
||||||
|
collection.Folder +
|
||||||
|
'|' + collection.Search +
|
||||||
|
'|' + MessagelistUserStore.threadUid() +
|
||||||
|
'|' + MessagelistUserStore.page()
|
||||||
|
);
|
||||||
|
MessagelistUserStore.endThreadUid(collection.ThreadUid);
|
||||||
|
const message = MessageUserStore.message();
|
||||||
|
if (message && collection.Folder !== message.folder) {
|
||||||
|
MessageUserStore.message(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.disableAutoSelect(true);
|
||||||
|
|
||||||
|
MessagelistUserStore(collection);
|
||||||
|
MessagelistUserStore.isIncomplete(false);
|
||||||
|
|
||||||
|
clearNewMessageCache();
|
||||||
|
|
||||||
|
if (folder && (bCached || unreadCountChange || SettingsUserStore.useThreads())) {
|
||||||
|
rl.app.folderInformation(folder.fullName, collection);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MessagelistUserStore.count(0);
|
||||||
|
MessagelistUserStore([]);
|
||||||
|
MessagelistUserStore.error(getNotification(Notification.CantGetMessageList));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessagelistUserStore.loading(false);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Folder: FolderUserStore.currentFolderFullName(),
|
||||||
|
Offset: iOffset,
|
||||||
|
Limit: SettingsUserStore.messagesPerPage(),
|
||||||
|
Search: MessagelistUserStore.listSearch(),
|
||||||
|
ThreadUid: MessagelistUserStore.threadUid()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullName
|
||||||
|
* @param {number} iSetAction
|
||||||
|
* @param {Array=} messages = null
|
||||||
|
*/
|
||||||
|
MessagelistUserStore.setAction = (sFolderFullName, iSetAction, messages) => {
|
||||||
|
messages = messages || MessagelistUserStore.listChecked();
|
||||||
|
|
||||||
|
let folder = null,
|
||||||
|
alreadyUnread = 0,
|
||||||
|
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null)
|
||||||
|
.validUnique(),
|
||||||
|
length = rootUids.length;
|
||||||
|
|
||||||
|
if (sFolderFullName && length) {
|
||||||
|
switch (iSetAction) {
|
||||||
|
case MessageSetAction.SetSeen:
|
||||||
|
length = 0;
|
||||||
|
// fallthrough is intentionally
|
||||||
|
case MessageSetAction.UnsetSeen:
|
||||||
|
rootUids.forEach(sSubUid =>
|
||||||
|
alreadyUnread += MessageFlagsCache.storeBySetAction(sFolderFullName, sSubUid, iSetAction)
|
||||||
|
);
|
||||||
|
|
||||||
|
folder = getFolderFromCacheList(sFolderFullName);
|
||||||
|
if (folder) {
|
||||||
|
folder.messageCountUnread(folder.messageCountUnread() - alreadyUnread + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.app.Remote.request('MessageSetSeen', null, {
|
||||||
|
Folder: sFolderFullName,
|
||||||
|
Uids: rootUids.join(','),
|
||||||
|
SetAction: iSetAction == MessageSetAction.SetSeen ? 1 : 0
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MessageSetAction.SetFlag:
|
||||||
|
case MessageSetAction.UnsetFlag:
|
||||||
|
rootUids.forEach(sSubUid =>
|
||||||
|
MessageFlagsCache.storeBySetAction(sFolderFullName, sSubUid, iSetAction)
|
||||||
|
);
|
||||||
|
rl.app.Remote.request('MessageSetFlagged', null, {
|
||||||
|
Folder: sFolderFullName,
|
||||||
|
Uids: rootUids.join(','),
|
||||||
|
SetAction: iSetAction == MessageSetAction.SetFlag ? 1 : 0
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
// no default
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} fromFolderFullName
|
||||||
|
* @param {Array} uidForRemove
|
||||||
|
* @param {string=} toFolderFullName = ''
|
||||||
|
* @param {boolean=} copy = false
|
||||||
|
*/
|
||||||
|
MessagelistUserStore.removeMessagesFromList = (
|
||||||
|
fromFolderFullName, uidForRemove, toFolderFullName = '', copy = false
|
||||||
|
) => {
|
||||||
|
uidForRemove = uidForRemove.map(mValue => pInt(mValue));
|
||||||
|
|
||||||
|
let unseenCount = 0,
|
||||||
|
messageList = MessagelistUserStore,
|
||||||
|
currentMessage = MessageUserStore.message();
|
||||||
|
|
||||||
|
const trashFolder = FolderUserStore.trashFolder(),
|
||||||
|
spamFolder = FolderUserStore.spamFolder(),
|
||||||
|
fromFolder = getFolderFromCacheList(fromFolderFullName),
|
||||||
|
toFolder = toFolderFullName ? getFolderFromCacheList(toFolderFullName) : null,
|
||||||
|
messages =
|
||||||
|
FolderUserStore.currentFolderFullName() === fromFolderFullName
|
||||||
|
? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid)))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
messages.forEach(item => {
|
||||||
|
if (item && item.isUnseen()) {
|
||||||
|
++unseenCount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fromFolder && !copy) {
|
||||||
|
fromFolder.messageCountAll(
|
||||||
|
0 <= fromFolder.messageCountAll() - uidForRemove.length ? fromFolder.messageCountAll() - uidForRemove.length : 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (0 < unseenCount) {
|
||||||
|
fromFolder.messageCountUnread(
|
||||||
|
0 <= fromFolder.messageCountUnread() - unseenCount ? fromFolder.messageCountUnread() - unseenCount : 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toFolder) {
|
||||||
|
if (trashFolder === toFolder.fullName || spamFolder === toFolder.fullName) {
|
||||||
|
unseenCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
toFolder.messageCountAll(toFolder.messageCountAll() + uidForRemove.length);
|
||||||
|
if (0 < unseenCount) {
|
||||||
|
toFolder.messageCountUnread(toFolder.messageCountUnread() + unseenCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
toFolder.actionBlink(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messages.length) {
|
||||||
|
if (copy) {
|
||||||
|
messages.forEach(item => item.checked(false));
|
||||||
|
} else {
|
||||||
|
MessagelistUserStore.isIncomplete(true);
|
||||||
|
|
||||||
|
messages.forEach(item => {
|
||||||
|
if (currentMessage && currentMessage.hash === item.hash) {
|
||||||
|
currentMessage = null;
|
||||||
|
MessageUserStore.message(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
item.deleted(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => messages.forEach(item => messageList.remove(item)), 350);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromFolderFullName) {
|
||||||
|
setFolderHash(fromFolderFullName, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toFolderFullName) {
|
||||||
|
setFolderHash(toFolderFullName, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MessagelistUserStore.threadUid()) {
|
||||||
|
if (
|
||||||
|
messageList.length &&
|
||||||
|
!!messageList.find(item => !!(item && item.deleted() && item.uid == MessagelistUserStore.threadUid()))
|
||||||
|
) {
|
||||||
|
const message = messageList.find(item => item && !item.deleted());
|
||||||
|
let setHash;
|
||||||
|
if (!message) {
|
||||||
|
if (1 < MessagelistUserStore.page()) {
|
||||||
|
MessagelistUserStore.page(MessagelistUserStore.page() - 1);
|
||||||
|
setHash = 1;
|
||||||
|
} else {
|
||||||
|
MessagelistUserStore.threadUid(0);
|
||||||
|
rl.route.setHash(
|
||||||
|
mailBox(
|
||||||
|
FolderUserStore.currentFolderFullNameHash(),
|
||||||
|
MessagelistUserStore.pageBeforeThread(),
|
||||||
|
MessagelistUserStore.listSearch()
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (MessagelistUserStore.threadUid() != message.uid) {
|
||||||
|
MessagelistUserStore.threadUid(message.uid);
|
||||||
|
setHash = 1;
|
||||||
|
}
|
||||||
|
if (setHash) {
|
||||||
|
rl.route.setHash(
|
||||||
|
mailBox(
|
||||||
|
FolderUserStore.currentFolderFullNameHash(),
|
||||||
|
MessagelistUserStore.page(),
|
||||||
|
MessagelistUserStore.listSearch(),
|
||||||
|
MessagelistUserStore.threadUid()
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
MessagelistUserStore.reloadFlagsAndCachedMessage = () => {
|
||||||
|
MessagelistUserStore.forEach(message => MessageFlagsCache.initMessage(message));
|
||||||
|
MessageFlagsCache.initMessage(MessageUserStore.message());
|
||||||
|
};
|
|
@ -2,7 +2,7 @@ import { koComputable } from 'External/ko';
|
||||||
|
|
||||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||||
|
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
@ -54,7 +54,7 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
|
||||||
submitForm() {
|
submitForm() {
|
||||||
const search = this.buildSearchString();
|
const search = this.buildSearchString();
|
||||||
if (search) {
|
if (search) {
|
||||||
MessageUserStore.mainMessageListSearch(search);
|
MessagelistUserStore.mainSearch(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cancelCommand();
|
this.cancelCommand();
|
||||||
|
|
|
@ -18,9 +18,9 @@ import { encodeHtml, HtmlEditor, htmlToPlain } from 'Common/Html';
|
||||||
import { koArrayWithDestroy } from 'External/ko';
|
import { koArrayWithDestroy } from 'External/ko';
|
||||||
|
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
|
import { messagesDeleteHelper } from 'Common/Folders';
|
||||||
import { serverRequest } from 'Common/Links';
|
import { serverRequest } from 'Common/Links';
|
||||||
import { i18n, getNotification, getUploadErrorDescByCode } from 'Common/Translator';
|
import { i18n, getNotification, getUploadErrorDescByCode, timestampToString } from 'Common/Translator';
|
||||||
import { timestampToString } from 'Common/Momentor';
|
|
||||||
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
|
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
|
||||||
import { doc, Settings, SettingsGet, getFullscreenElement, exitFullscreen, elementById } from 'Common/Globals';
|
import { doc, Settings, SettingsGet, getFullscreenElement, exitFullscreen, elementById } from 'Common/Globals';
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import { PgpUserStore } from 'Stores/User/Pgp';
|
||||||
import { OpenPGPUserStore } from 'Stores/User/OpenPGP';
|
import { OpenPGPUserStore } from 'Stores/User/OpenPGP';
|
||||||
import { GnuPGUserStore } from 'Stores/User/GnuPG';
|
import { GnuPGUserStore } from 'Stores/User/GnuPG';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
|
@ -521,7 +522,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
if (isArray(flagsCache)) {
|
if (isArray(flagsCache)) {
|
||||||
flagsCache.push(('forward' === this.aDraftInfo[0]) ? '$forwarded' : '\\answered');
|
flagsCache.push(('forward' === this.aDraftInfo[0]) ? '$forwarded' : '\\answered');
|
||||||
MessageFlagsCache.setFor(this.aDraftInfo[2], this.aDraftInfo[1], flagsCache);
|
MessageFlagsCache.setFor(this.aDraftInfo[2], this.aDraftInfo[1], flagsCache);
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
setFolderHash(this.aDraftInfo[2], '');
|
setFolderHash(this.aDraftInfo[2], '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,8 +633,8 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
const
|
const
|
||||||
sFromFolderFullName = this.draftsFolder(),
|
sFromFolderFullName = this.draftsFolder(),
|
||||||
aUidForRemove = [this.draftUid()];
|
aUidForRemove = [this.draftUid()];
|
||||||
rl.app.messagesDeleteHelper(sFromFolderFullName, aUidForRemove);
|
messagesDeleteHelper(sFromFolderFullName, aUidForRemove);
|
||||||
MessageUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove);
|
MessagelistUserStore.removeMessagesFromList(sFromFolderFullName, aUidForRemove);
|
||||||
this.closeCommand();
|
this.closeCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,8 +685,18 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
}, 60000);
|
}, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getAutocomplete
|
||||||
emailsSource(oData, fResponse) {
|
emailsSource(oData, fResponse) {
|
||||||
rl.app.getAutocomplete(oData.term, aData => fResponse(aData.map(oEmailItem => oEmailItem.toLine(false))));
|
Remote.suggestions((iError, data) => {
|
||||||
|
if (!iError && isArray(data.Result)) {
|
||||||
|
fResponse(
|
||||||
|
data.Result.map(item => (item && item[0] ? (new EmailModel(item[0], item[1])).toLine(false) : null))
|
||||||
|
.filter(v => v)
|
||||||
|
);
|
||||||
|
} else if (Notification.RequestAborted !== iError) {
|
||||||
|
fResponse([]);
|
||||||
|
}
|
||||||
|
}, oData.term);
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadDraftFolder() {
|
reloadDraftFolder() {
|
||||||
|
@ -693,7 +704,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
if (draftsFolder && UNUSED_OPTION_VALUE !== draftsFolder) {
|
if (draftsFolder && UNUSED_OPTION_VALUE !== draftsFolder) {
|
||||||
setFolderHash(draftsFolder, '');
|
setFolderHash(draftsFolder, '');
|
||||||
if (FolderUserStore.currentFolderFullName() === draftsFolder) {
|
if (FolderUserStore.currentFolderFullName() === draftsFolder) {
|
||||||
rl.app.reloadMessageList(true);
|
MessagelistUserStore.reload(true);
|
||||||
} else {
|
} else {
|
||||||
rl.app.folderInformation(draftsFolder);
|
rl.app.folderInformation(draftsFolder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { SieveUserStore } from 'Stores/User/Sieve';
|
||||||
|
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
|
||||||
import { folderListOptionsBuilder } from 'Common/UtilsUser';
|
import { folderListOptionsBuilder } from 'Common/Folders';
|
||||||
|
|
||||||
class FilterPopupView extends AbstractViewPopup {
|
class FilterPopupView extends AbstractViewPopup {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { i18n, getNotification } from 'Common/Translator';
|
||||||
import { setFolderHash } from 'Common/Cache';
|
import { setFolderHash } from 'Common/Cache';
|
||||||
|
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ class FolderClearPopupView extends AbstractViewPopup {
|
||||||
const folderToClear = this.selectedFolder();
|
const folderToClear = this.selectedFolder();
|
||||||
if (folderToClear) {
|
if (folderToClear) {
|
||||||
MessageUserStore.message(null);
|
MessageUserStore.message(null);
|
||||||
MessageUserStore.list([]);
|
MessagelistUserStore([]);
|
||||||
|
|
||||||
this.clearingProcess(true);
|
this.clearingProcess(true);
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ class FolderClearPopupView extends AbstractViewPopup {
|
||||||
if (iError) {
|
if (iError) {
|
||||||
this.clearingError(getNotification(iError));
|
this.clearingError(getNotification(iError));
|
||||||
} else {
|
} else {
|
||||||
rl.app.reloadMessageList(true);
|
MessagelistUserStore.reload(true);
|
||||||
this.cancelCommand();
|
this.cancelCommand();
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { koComputable } from 'External/ko';
|
||||||
import { Notification } from 'Common/Enums';
|
import { Notification } from 'Common/Enums';
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
import { defaultOptionsAfterRender } from 'Common/Utils';
|
import { defaultOptionsAfterRender } from 'Common/Utils';
|
||||||
import { folderListOptionsBuilder, sortFolders } from 'Common/UtilsUser';
|
import { folderListOptionsBuilder, sortFolders } from 'Common/Folders';
|
||||||
import { getNotification } from 'Common/Translator';
|
import { getNotification } from 'Common/Translator';
|
||||||
|
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { koComputable, addSubscribablesTo } from 'External/ko';
|
||||||
import { SetSystemFoldersNotification } from 'Common/EnumsUser';
|
import { SetSystemFoldersNotification } from 'Common/EnumsUser';
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
import { defaultOptionsAfterRender } from 'Common/Utils';
|
import { defaultOptionsAfterRender } from 'Common/Utils';
|
||||||
import { folderListOptionsBuilder } from 'Common/UtilsUser';
|
import { folderListOptionsBuilder } from 'Common/Folders';
|
||||||
import { initOnStartOrLangChange, i18n } from 'Common/Translator';
|
import { initOnStartOrLangChange, i18n } from 'Common/Translator';
|
||||||
|
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { AppUserStore } from 'Stores/User/App';
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
|
|
||||||
import { showScreenPopup } from 'Knoin/Knoin';
|
import { showScreenPopup } from 'Knoin/Knoin';
|
||||||
import { AbstractViewLeft } from 'Knoin/AbstractViews';
|
import { AbstractViewLeft } from 'Knoin/AbstractViews';
|
||||||
|
@ -22,6 +23,8 @@ import { isArray } from 'Common/Utils';
|
||||||
import { ClientSideKeyName } from 'Common/EnumsUser';
|
import { ClientSideKeyName } from 'Common/EnumsUser';
|
||||||
import * as Local from 'Storage/Client';
|
import * as Local from 'Storage/Client';
|
||||||
|
|
||||||
|
import { moveMessagesToFolder } from 'Common/Folders';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} sFullName
|
* @param {string} sFullName
|
||||||
* @param {boolean} bExpanded
|
* @param {boolean} bExpanded
|
||||||
|
@ -109,9 +112,9 @@ export class MailFolderList extends AbstractViewLeft {
|
||||||
if (folder) {
|
if (folder) {
|
||||||
if (moveAction()) {
|
if (moveAction()) {
|
||||||
moveAction(false);
|
moveAction(false);
|
||||||
rl.app.moveMessagesToFolder(
|
moveMessagesToFolder(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
folder.fullName,
|
folder.fullName,
|
||||||
event.ctrlKey
|
event.ctrlKey
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,8 +15,9 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
|
|
||||||
import { doc, leftPanelDisabled, moveAction, Settings, SettingsCapa, SettingsGet, fireEvent } from 'Common/Globals';
|
import { doc, leftPanelDisabled, moveAction, Settings, SettingsCapa, SettingsGet, fireEvent } from 'Common/Globals';
|
||||||
|
|
||||||
import { computedPaginatorHelper, showMessageComposer, folderListOptionsBuilder } from 'Common/UtilsUser';
|
import { computedPaginatorHelper, showMessageComposer, populateMessageBody } from 'Common/UtilsUser';
|
||||||
import { FileInfo } from 'Common/File';
|
import { FileInfo } from 'Common/File';
|
||||||
|
import { folderListOptionsBuilder, moveMessagesToFolder } from 'Common/Folders';
|
||||||
|
|
||||||
import { mailBox, serverRequest } from 'Common/Links';
|
import { mailBox, serverRequest } from 'Common/Links';
|
||||||
import { Selector } from 'Common/Selector';
|
import { Selector } from 'Common/Selector';
|
||||||
|
@ -34,6 +35,7 @@ import { AppUserStore } from 'Stores/User/App';
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
import Remote from 'Remote/User/Fetch';
|
import Remote from 'Remote/User/Fetch';
|
||||||
|
@ -44,8 +46,18 @@ import { AbstractViewRight } from 'Knoin/AbstractViews';
|
||||||
import { FolderClearPopupView } from 'View/Popup/FolderClear';
|
import { FolderClearPopupView } from 'View/Popup/FolderClear';
|
||||||
import { AdvancedSearchPopupView } from 'View/Popup/AdvancedSearch';
|
import { AdvancedSearchPopupView } from 'View/Popup/AdvancedSearch';
|
||||||
|
|
||||||
|
import { MessageModel } from 'Model/Message';
|
||||||
|
|
||||||
const
|
const
|
||||||
canBeMovedHelper = () => MessageUserStore.hasCheckedOrSelected();
|
canBeMovedHelper = () => MessagelistUserStore.hasCheckedOrSelected(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullName
|
||||||
|
* @param {number} iSetAction
|
||||||
|
* @param {Array=} aMessages = null
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
listAction = (...args) => MessagelistUserStore.setAction(...args);
|
||||||
|
|
||||||
export class MailMessageList extends AbstractViewRight {
|
export class MailMessageList extends AbstractViewRight {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -62,23 +74,23 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
this.allowSearchAdv = SettingsCapa(Capa.SearchAdv);
|
this.allowSearchAdv = SettingsCapa(Capa.SearchAdv);
|
||||||
this.allowDangerousActions = SettingsCapa(Capa.DangerousActions);
|
this.allowDangerousActions = SettingsCapa(Capa.DangerousActions);
|
||||||
|
|
||||||
this.messageList = MessageUserStore.list;
|
this.messageList = MessagelistUserStore;
|
||||||
|
|
||||||
this.composeInEdit = AppUserStore.composeInEdit;
|
this.composeInEdit = AppUserStore.composeInEdit;
|
||||||
|
|
||||||
this.isMobile = ThemeStore.isMobile;
|
this.isMobile = ThemeStore.isMobile;
|
||||||
this.leftPanelDisabled = leftPanelDisabled;
|
this.leftPanelDisabled = leftPanelDisabled;
|
||||||
|
|
||||||
this.messageListSearch = MessageUserStore.listSearch;
|
this.messageListSearch = MessagelistUserStore.listSearch;
|
||||||
this.messageListError = MessageUserStore.listError;
|
this.messageListError = MessagelistUserStore.error;
|
||||||
|
|
||||||
this.popupVisibility = arePopupsVisible;
|
this.popupVisibility = arePopupsVisible;
|
||||||
|
|
||||||
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
|
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
|
||||||
|
|
||||||
this.messageListThreadUid = MessageUserStore.listEndThreadUid;
|
this.messageListThreadUid = MessagelistUserStore.endThreadUid;
|
||||||
|
|
||||||
this.messageListIsLoading = MessageUserStore.listIsLoading;
|
this.messageListIsLoading = MessagelistUserStore.isLoading;
|
||||||
|
|
||||||
initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'));
|
initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'));
|
||||||
|
|
||||||
|
@ -114,44 +126,44 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
),
|
),
|
||||||
|
|
||||||
messageListSearchDesc: () => {
|
messageListSearchDesc: () => {
|
||||||
const value = MessageUserStore.list().Search;
|
const value = MessagelistUserStore().Search;
|
||||||
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { SEARCH: value }) : ''
|
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { SEARCH: value }) : ''
|
||||||
},
|
},
|
||||||
|
|
||||||
messageListPaginator: computedPaginatorHelper(MessageUserStore.listPage,
|
messageListPaginator: computedPaginatorHelper(MessagelistUserStore.page,
|
||||||
MessageUserStore.listPageCount),
|
MessagelistUserStore.pageCount),
|
||||||
|
|
||||||
checkAll: {
|
checkAll: {
|
||||||
read: () => 0 < MessageUserStore.listChecked().length,
|
read: () => 0 < MessagelistUserStore.listChecked().length,
|
||||||
write: (value) => {
|
write: (value) => {
|
||||||
value = !!value;
|
value = !!value;
|
||||||
MessageUserStore.list.forEach(message => message.checked(value));
|
MessagelistUserStore.forEach(message => message.checked(value));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
inputProxyMessageListSearch: {
|
inputProxyMessageListSearch: {
|
||||||
read: MessageUserStore.mainMessageListSearch,
|
read: MessagelistUserStore.mainSearch,
|
||||||
write: value => this.sLastSearchValue = value
|
write: value => this.sLastSearchValue = value
|
||||||
},
|
},
|
||||||
|
|
||||||
isIncompleteChecked: () => {
|
isIncompleteChecked: () => {
|
||||||
const c = MessageUserStore.listChecked().length;
|
const c = MessagelistUserStore.listChecked().length;
|
||||||
return c && MessageUserStore.list.length > c;
|
return c && MessagelistUserStore().length > c;
|
||||||
},
|
},
|
||||||
|
|
||||||
hasMessages: () => 0 < MessageUserStore.list().length,
|
hasMessages: () => 0 < MessagelistUserStore().length,
|
||||||
|
|
||||||
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessageUserStore.list().Folder,
|
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessagelistUserStore().Folder,
|
||||||
|
|
||||||
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(),
|
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(),
|
||||||
|
|
||||||
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessageUserStore.list().Folder,
|
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessagelistUserStore().Folder,
|
||||||
|
|
||||||
isDraftFolder: () => (FolderUserStore.draftsFolder() || 0) === MessageUserStore.list().Folder,
|
isDraftFolder: () => (FolderUserStore.draftsFolder() || 0) === MessagelistUserStore().Folder,
|
||||||
|
|
||||||
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessageUserStore.list().Folder,
|
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessagelistUserStore().Folder,
|
||||||
|
|
||||||
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessageUserStore.list().Folder,
|
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessagelistUserStore().Folder,
|
||||||
|
|
||||||
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(),
|
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(),
|
||||||
|
|
||||||
|
@ -163,9 +175,9 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
isUnSpamVisible: () =>
|
isUnSpamVisible: () =>
|
||||||
this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
||||||
|
|
||||||
mobileCheckedStateShow: () => ThemeStore.isMobile() ? 0 < MessageUserStore.listChecked().length : true,
|
mobileCheckedStateShow: () => ThemeStore.isMobile() ? 0 < MessagelistUserStore.listChecked().length : true,
|
||||||
|
|
||||||
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessageUserStore.listChecked().length : true,
|
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessagelistUserStore.listChecked().length : true,
|
||||||
|
|
||||||
sortText: () => {
|
sortText: () => {
|
||||||
let mode = FolderUserStore.sortMode(),
|
let mode = FolderUserStore.sortMode(),
|
||||||
|
@ -181,20 +193,27 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hasCheckedOrSelectedLines = MessageUserStore.hasCheckedOrSelected,
|
this.hasCheckedOrSelectedLines = MessagelistUserStore.hasCheckedOrSelected,
|
||||||
|
|
||||||
this.selector = new Selector(
|
this.selector = new Selector(
|
||||||
MessageUserStore.list,
|
MessagelistUserStore,
|
||||||
MessageUserStore.selectorMessageSelected,
|
MessagelistUserStore.selectedMessage,
|
||||||
MessageUserStore.selectorMessageFocused,
|
MessagelistUserStore.focusedMessage,
|
||||||
'.messageListItem .actionHandle',
|
'.messageListItem .actionHandle',
|
||||||
'.messageListItem .checkboxMessage',
|
'.messageListItem .checkboxMessage',
|
||||||
'.messageListItem.focused'
|
'.messageListItem.focused'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.selector.on('ItemSelect', message => MessageUserStore.selectMessage(message));
|
this.selector.on('ItemSelect', message => {
|
||||||
|
if (message) {
|
||||||
|
MessageUserStore.message(MessageModel.fromMessageListItem(message));
|
||||||
|
populateMessageBody(MessageUserStore.message());
|
||||||
|
} else {
|
||||||
|
MessageUserStore.message(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.selector.on('MiddleClick', message => MessageUserStore.populateMessageBody(message, true));
|
this.selector.on('MiddleClick', message => populateMessageBody(message, true));
|
||||||
|
|
||||||
this.selector.on('ItemGetUid', message => (message ? message.generateUid() : ''));
|
this.selector.on('ItemGetUid', message => (message ? message.generateUid() : ''));
|
||||||
|
|
||||||
|
@ -213,7 +232,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
addEventListener('mailbox.message.show', e => {
|
addEventListener('mailbox.message.show', e => {
|
||||||
const sFolder = e.detail.Folder, iUid = e.detail.Uid;
|
const sFolder = e.detail.Folder, iUid = e.detail.Uid;
|
||||||
|
|
||||||
const message = MessageUserStore.list.find(
|
const message = MessagelistUserStore.find(
|
||||||
item => item && sFolder === item.folder && iUid == item.uid
|
item => item && sFolder === item.folder && iUid == item.uid
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -227,12 +246,19 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
if ('INBOX' !== sFolder) {
|
if ('INBOX' !== sFolder) {
|
||||||
rl.route.setHash(mailBox(sFolder));
|
rl.route.setHash(mailBox(sFolder));
|
||||||
}
|
}
|
||||||
|
if (sFolder && iUid) {
|
||||||
|
MessageUserStore.message(MessageModel.fromMessageListItem(null));
|
||||||
|
MessageUserStore.message().folder = sFolder;
|
||||||
|
MessageUserStore.message().uid = iUid;
|
||||||
|
|
||||||
MessageUserStore.selectMessageByFolderAndUid(sFolder, iUid);
|
populateMessageBody(MessageUserStore.message());
|
||||||
|
} else {
|
||||||
|
MessageUserStore.message(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageUserStore.listEndHash.subscribe((() =>
|
MessagelistUserStore.endHash.subscribe((() =>
|
||||||
this.selector.scrollToFocused()
|
this.selector.scrollToFocused()
|
||||||
).throttle(50));
|
).throttle(50));
|
||||||
|
|
||||||
|
@ -260,15 +286,15 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
if (!MessageUserStore.listIsLoading()) {
|
if (!MessagelistUserStore.isLoading()) {
|
||||||
rl.app.reloadMessageList(false, true);
|
MessagelistUserStore.reload(false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
multyForwardCommand() {
|
multyForwardCommand() {
|
||||||
showMessageComposer([
|
showMessageComposer([
|
||||||
ComposeType.ForwardAsAttachment,
|
ComposeType.ForwardAsAttachment,
|
||||||
MessageUserStore.listCheckedOrSelected()
|
MessagelistUserStore.listCheckedOrSelected()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +303,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
rl.app.deleteMessagesFromFolder(
|
rl.app.deleteMessagesFromFolder(
|
||||||
FolderType.Trash,
|
FolderType.Trash,
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -287,7 +313,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
rl.app.deleteMessagesFromFolder(
|
rl.app.deleteMessagesFromFolder(
|
||||||
FolderType.Trash,
|
FolderType.Trash,
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -296,7 +322,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
rl.app.deleteMessagesFromFolder(
|
rl.app.deleteMessagesFromFolder(
|
||||||
FolderType.Archive,
|
FolderType.Archive,
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +331,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
rl.app.deleteMessagesFromFolder(
|
rl.app.deleteMessagesFromFolder(
|
||||||
FolderType.Spam,
|
FolderType.Spam,
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -314,7 +340,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
rl.app.deleteMessagesFromFolder(
|
rl.app.deleteMessagesFromFolder(
|
||||||
FolderType.NotSpam,
|
FolderType.NotSpam,
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -339,7 +365,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
|
|
||||||
goToUpOrDown(up) {
|
goToUpOrDown(up) {
|
||||||
if (MessageUserStore.listChecked().length) {
|
if (MessagelistUserStore.listChecked().length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,27 +410,28 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
|
|
||||||
useAutoSelect() {
|
useAutoSelect() {
|
||||||
return !MessageUserStore.listDisableAutoSelect()
|
return !MessagelistUserStore.disableAutoSelect()
|
||||||
&& !/is:unseen/.test(MessageUserStore.mainMessageListSearch())
|
&& !/is:unseen/.test(MessagelistUserStore.mainSearch())
|
||||||
&& SettingsUserStore.usePreviewPane();
|
&& SettingsUserStore.usePreviewPane();
|
||||||
}
|
}
|
||||||
|
|
||||||
searchEnterAction() {
|
searchEnterAction() {
|
||||||
MessageUserStore.mainMessageListSearch(this.sLastSearchValue);
|
MessagelistUserStore.mainSearch(this.sLastSearchValue);
|
||||||
this.inputMessageListSearchFocus(false);
|
this.inputMessageListSearchFocus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelSearch() {
|
cancelSearch() {
|
||||||
MessageUserStore.mainMessageListSearch('');
|
MessagelistUserStore.mainSearch('');
|
||||||
this.inputMessageListSearchFocus(false);
|
this.inputMessageListSearchFocus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelThreadUid() {
|
cancelThreadUid() {
|
||||||
|
// history.go(-1) better?
|
||||||
rl.route.setHash(
|
rl.route.setHash(
|
||||||
mailBox(
|
mailBox(
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
FolderUserStore.currentFolderFullNameHash(),
|
||||||
MessageUserStore.listPageBeforeThread(),
|
MessagelistUserStore.pageBeforeThread(),
|
||||||
MessageUserStore.listSearch()
|
MessagelistUserStore.listSearch()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -415,10 +442,10 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
moveSelectedMessagesToFolder(sToFolderFullName, bCopy) {
|
moveSelectedMessagesToFolder(sToFolderFullName, bCopy) {
|
||||||
if (MessageUserStore.hasCheckedOrSelected()) {
|
if (MessagelistUserStore.hasCheckedOrSelected()) {
|
||||||
rl.app.moveMessagesToFolder(
|
moveMessagesToFolder(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(),
|
||||||
sToFolderFullName,
|
sToFolderFullName,
|
||||||
bCopy
|
bCopy
|
||||||
);
|
);
|
||||||
|
@ -430,7 +457,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
getDragData(event) {
|
getDragData(event) {
|
||||||
const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY));
|
const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY));
|
||||||
item && item.checked && item.checked(true);
|
item && item.checked && item.checked(true);
|
||||||
const uids = MessageUserStore.listCheckedOrSelectedUidsWithSubMails();
|
const uids = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails();
|
||||||
item && !uids.includes(item.uid) && uids.push(item.uid);
|
item && !uids.includes(item.uid) && uids.push(item.uid);
|
||||||
return uids.length ? {
|
return uids.length ? {
|
||||||
copy: event.ctrlKey,
|
copy: event.ctrlKey,
|
||||||
|
@ -439,34 +466,24 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
} : null;
|
} : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} sFolderFullName
|
|
||||||
* @param {number} iSetAction
|
|
||||||
* @param {Array=} aMessages = null
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
setAction(sFolderFullName, iSetAction, aMessages) {
|
|
||||||
rl.app.messageListAction(sFolderFullName, iSetAction, aMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
listSetSeen() {
|
listSetSeen() {
|
||||||
this.setAction(
|
listAction(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageSetAction.SetSeen,
|
MessageSetAction.SetSeen,
|
||||||
MessageUserStore.listCheckedOrSelected()
|
MessagelistUserStore.listCheckedOrSelected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
listSetAllSeen() {
|
listSetAllSeen() {
|
||||||
let sFolderFullName = FolderUserStore.currentFolderFullName(),
|
let sFolderFullName = FolderUserStore.currentFolderFullName(),
|
||||||
iThreadUid = MessageUserStore.listEndThreadUid();
|
iThreadUid = MessagelistUserStore.endThreadUid();
|
||||||
if (sFolderFullName) {
|
if (sFolderFullName) {
|
||||||
let cnt = 0;
|
let cnt = 0;
|
||||||
const uids = [];
|
const uids = [];
|
||||||
|
|
||||||
let folder = getFolderFromCacheList(sFolderFullName);
|
let folder = getFolderFromCacheList(sFolderFullName);
|
||||||
if (folder) {
|
if (folder) {
|
||||||
MessageUserStore.list.forEach(message => {
|
MessagelistUserStore.forEach(message => {
|
||||||
if (message.isUnseen()) {
|
if (message.isUnseen()) {
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
|
@ -486,47 +503,47 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
Remote.messageSetSeenToAll(sFolderFullName, true, iThreadUid ? uids : null);
|
Remote.messageSetSeenToAll(sFolderFullName, true, iThreadUid ? uids : null);
|
||||||
|
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listUnsetSeen() {
|
listUnsetSeen() {
|
||||||
this.setAction(
|
listAction(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageSetAction.UnsetSeen,
|
MessageSetAction.UnsetSeen,
|
||||||
MessageUserStore.listCheckedOrSelected()
|
MessagelistUserStore.listCheckedOrSelected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
listSetFlags() {
|
listSetFlags() {
|
||||||
this.setAction(
|
listAction(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageSetAction.SetFlag,
|
MessageSetAction.SetFlag,
|
||||||
MessageUserStore.listCheckedOrSelected()
|
MessagelistUserStore.listCheckedOrSelected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
listUnsetFlags() {
|
listUnsetFlags() {
|
||||||
this.setAction(
|
listAction(
|
||||||
FolderUserStore.currentFolderFullName(),
|
FolderUserStore.currentFolderFullName(),
|
||||||
MessageSetAction.UnsetFlag,
|
MessageSetAction.UnsetFlag,
|
||||||
MessageUserStore.listCheckedOrSelected()
|
MessagelistUserStore.listCheckedOrSelected()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
flagMessages(currentMessage) {
|
flagMessages(currentMessage) {
|
||||||
const checked = MessageUserStore.listCheckedOrSelected();
|
const checked = MessagelistUserStore.listCheckedOrSelected();
|
||||||
if (currentMessage) {
|
if (currentMessage) {
|
||||||
const checkedUids = checked.map(message => message.uid);
|
const checkedUids = checked.map(message => message.uid);
|
||||||
if (checkedUids.includes(currentMessage.uid)) {
|
if (checkedUids.includes(currentMessage.uid)) {
|
||||||
this.setAction(
|
listAction(
|
||||||
currentMessage.folder,
|
currentMessage.folder,
|
||||||
currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
||||||
checked
|
checked
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.setAction(
|
listAction(
|
||||||
currentMessage.folder,
|
currentMessage.folder,
|
||||||
currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
currentMessage.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
||||||
[currentMessage]
|
[currentMessage]
|
||||||
|
@ -536,17 +553,17 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
|
|
||||||
flagMessagesFast(bFlag) {
|
flagMessagesFast(bFlag) {
|
||||||
const checked = MessageUserStore.listCheckedOrSelected();
|
const checked = MessagelistUserStore.listCheckedOrSelected();
|
||||||
if (checked.length) {
|
if (checked.length) {
|
||||||
if (undefined === bFlag) {
|
if (undefined === bFlag) {
|
||||||
const flagged = checked.filter(message => message.isFlagged());
|
const flagged = checked.filter(message => message.isFlagged());
|
||||||
this.setAction(
|
listAction(
|
||||||
checked[0].folder,
|
checked[0].folder,
|
||||||
checked.length === flagged.length ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
checked.length === flagged.length ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
||||||
checked
|
checked
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.setAction(
|
listAction(
|
||||||
checked[0].folder,
|
checked[0].folder,
|
||||||
!bFlag ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
!bFlag ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
||||||
checked
|
checked
|
||||||
|
@ -556,17 +573,17 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
}
|
}
|
||||||
|
|
||||||
seenMessagesFast(seen) {
|
seenMessagesFast(seen) {
|
||||||
const checked = MessageUserStore.listCheckedOrSelected();
|
const checked = MessagelistUserStore.listCheckedOrSelected();
|
||||||
if (checked.length) {
|
if (checked.length) {
|
||||||
if (undefined === seen) {
|
if (undefined === seen) {
|
||||||
const unseen = checked.filter(message => message.isUnseen());
|
const unseen = checked.filter(message => message.isUnseen());
|
||||||
this.setAction(
|
listAction(
|
||||||
checked[0].folder,
|
checked[0].folder,
|
||||||
unseen.length ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen,
|
unseen.length ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen,
|
||||||
checked
|
checked
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.setAction(
|
listAction(
|
||||||
checked[0].folder,
|
checked[0].folder,
|
||||||
seen ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen,
|
seen ? MessageSetAction.SetSeen : MessageSetAction.UnsetSeen,
|
||||||
checked
|
checked
|
||||||
|
@ -580,28 +597,28 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
mailBox(
|
mailBox(
|
||||||
FolderUserStore.currentFolderFullNameHash(),
|
FolderUserStore.currentFolderFullNameHash(),
|
||||||
page.value,
|
page.value,
|
||||||
MessageUserStore.listSearch(),
|
MessagelistUserStore.listSearch(),
|
||||||
MessageUserStore.listThreadUid()
|
MessagelistUserStore.threadUid()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
gotoThread(message) {
|
gotoThread(message) {
|
||||||
if (message && 0 < message.threadsLen()) {
|
if (message && 0 < message.threadsLen()) {
|
||||||
MessageUserStore.listPageBeforeThread(MessageUserStore.listPage());
|
MessagelistUserStore.pageBeforeThread(MessagelistUserStore.page());
|
||||||
|
|
||||||
rl.route.setHash(
|
rl.route.setHash(
|
||||||
mailBox(FolderUserStore.currentFolderFullNameHash(), 1, MessageUserStore.listSearch(), message.uid)
|
mailBox(FolderUserStore.currentFolderFullNameHash(), 1, MessagelistUserStore.listSearch(), message.uid)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listEmptyMessage() {
|
listEmptyMessage() {
|
||||||
if (!this.dragOver()
|
if (!this.dragOver()
|
||||||
&& !MessageUserStore.list().length
|
&& !MessagelistUserStore().length
|
||||||
&& !MessageUserStore.listIsLoading()
|
&& !MessagelistUserStore.isLoading()
|
||||||
&& !MessageUserStore.listError()) {
|
&& !MessagelistUserStore.error()) {
|
||||||
return i18n('MESSAGE_LIST/EMPTY_' + (MessageUserStore.listSearch() ? 'SEARCH_' : '') + 'LIST');
|
return i18n('MESSAGE_LIST/EMPTY_' + (MessagelistUserStore.listSearch() ? 'SEARCH_' : '') + 'LIST');
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -609,9 +626,9 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
clearListIsVisible() {
|
clearListIsVisible() {
|
||||||
return (
|
return (
|
||||||
!this.messageListSearchDesc() &&
|
!this.messageListSearchDesc() &&
|
||||||
!MessageUserStore.listError() &&
|
!MessagelistUserStore.error() &&
|
||||||
!MessageUserStore.listEndThreadUid() &&
|
!MessagelistUserStore.endThreadUid() &&
|
||||||
MessageUserStore.list().length &&
|
MessagelistUserStore().length &&
|
||||||
(this.isSpamFolder() || this.isTrashFolder())
|
(this.isSpamFolder() || this.isTrashFolder())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -668,13 +685,13 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
.on('onBodyDragLeave', () => this.dragOver(false))
|
.on('onBodyDragLeave', () => this.dragOver(false))
|
||||||
.on('onSelect', (sUid, oData) => {
|
.on('onSelect', (sUid, oData) => {
|
||||||
if (sUid && oData && 'message/rfc822' === oData.Type) {
|
if (sUid && oData && 'message/rfc822' === oData.Type) {
|
||||||
MessageUserStore.listLoading(true);
|
MessagelistUserStore.loading(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.on('onComplete', () => rl.app.reloadMessageList(true, true));
|
.on('onComplete', () => MessagelistUserStore.reload(true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// initShortcuts
|
// initShortcuts
|
||||||
|
@ -694,12 +711,12 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
shortcuts.add('delete', 'shift', Scope.MessageList, () => {
|
shortcuts.add('delete', 'shift', Scope.MessageList, () => {
|
||||||
MessageUserStore.listCheckedOrSelected().length && this.deleteWithoutMoveCommand();
|
MessagelistUserStore.listCheckedOrSelected().length && this.deleteWithoutMoveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
// shortcuts.add('3', 'shift', Scope.MessageList, () => {
|
// shortcuts.add('3', 'shift', Scope.MessageList, () => {
|
||||||
shortcuts.add('delete', '', Scope.MessageList, () => {
|
shortcuts.add('delete', '', Scope.MessageList, () => {
|
||||||
MessageUserStore.listCheckedOrSelected().length && this.deleteCommand();
|
MessagelistUserStore.listCheckedOrSelected().length && this.deleteCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -728,9 +745,9 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('t', '', [Scope.MessageList], () => {
|
shortcuts.add('t', '', [Scope.MessageList], () => {
|
||||||
let message = MessageUserStore.selectorMessageSelected();
|
let message = MessagelistUserStore.selectedMessage();
|
||||||
if (!message) {
|
if (!message) {
|
||||||
message = MessageUserStore.selectorMessageFocused();
|
message = MessagelistUserStore.focusedMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message && 0 < message.threadsLen()) {
|
if (message && 0 < message.threadsLen()) {
|
||||||
|
@ -781,7 +798,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
if (this.messageListSearchDesc()) {
|
if (this.messageListSearchDesc()) {
|
||||||
this.cancelSearch();
|
this.cancelSearch();
|
||||||
return false;
|
return false;
|
||||||
} else if (MessageUserStore.listEndThreadUid()) {
|
} else if (MessagelistUserStore.endThreadUid()) {
|
||||||
this.cancelThreadUid();
|
this.cancelThreadUid();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -813,7 +830,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
prefetchNextTick() {
|
prefetchNextTick() {
|
||||||
if (!this.bPrefetch && !ifvisible.now() && !this.viewModelDom.hidden) {
|
if (!this.bPrefetch && !ifvisible.now() && !this.viewModelDom.hidden) {
|
||||||
const message = MessageUserStore.list.find(
|
const message = MessagelistUserStore.find(
|
||||||
item => item && !hasRequestedMessage(item.folder, item.uid)
|
item => item && !hasRequestedMessage(item.folder, item.uid)
|
||||||
);
|
);
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -838,7 +855,7 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
advancedSearchClick() {
|
advancedSearchClick() {
|
||||||
SettingsCapa(Capa.SearchAdv)
|
SettingsCapa(Capa.SearchAdv)
|
||||||
&& showScreenPopup(AdvancedSearchPopupView, [MessageUserStore.mainMessageListSearch()]);
|
&& showScreenPopup(AdvancedSearchPopupView, [MessagelistUserStore.mainSearch()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
quotaTooltip() {
|
quotaTooltip() {
|
||||||
|
|
|
@ -42,6 +42,7 @@ import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
import { AccountUserStore } from 'Stores/User/Account';
|
import { AccountUserStore } from 'Stores/User/Account';
|
||||||
import { FolderUserStore } from 'Stores/User/Folder';
|
import { FolderUserStore } from 'Stores/User/Folder';
|
||||||
import { MessageUserStore } from 'Stores/User/Message';
|
import { MessageUserStore } from 'Stores/User/Message';
|
||||||
|
import { MessagelistUserStore } from 'Stores/User/Messagelist';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
import * as Local from 'Storage/Client';
|
import * as Local from 'Storage/Client';
|
||||||
|
@ -66,10 +67,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
|
|
||||||
const
|
const
|
||||||
createCommandReplyHelper = type =>
|
createCommandReplyHelper = type =>
|
||||||
createCommand(() => {
|
createCommand(() => this.replyOrforward(type), this.canBeRepliedOrForwarded),
|
||||||
this.lastReplyAction(type);
|
|
||||||
this.replyOrforward(type);
|
|
||||||
}, this.canBeRepliedOrForwarded),
|
|
||||||
|
|
||||||
createCommandActionHelper = (folderType, useFolder) =>
|
createCommandActionHelper = (folderType, useFolder) =>
|
||||||
createCommand(() => {
|
createCommand(() => {
|
||||||
|
@ -101,13 +99,12 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
this.attachmentsActions = ko.observableArray(arrayLength(attachmentsActions) ? attachmentsActions : []);
|
this.attachmentsActions = ko.observableArray(arrayLength(attachmentsActions) ? attachmentsActions : []);
|
||||||
|
|
||||||
this.message = MessageUserStore.message;
|
this.message = MessageUserStore.message;
|
||||||
this.hasCheckedMessages = MessageUserStore.hasCheckedMessages;
|
this.hasCheckedMessages = MessagelistUserStore.hasCheckedMessages;
|
||||||
this.messageLoadingThrottle = MessageUserStore.messageLoading;
|
this.messageLoadingThrottle = MessageUserStore.loading;
|
||||||
this.messagesBodiesDom = MessageUserStore.messagesBodiesDom;
|
this.messagesBodiesDom = MessageUserStore.bodiesDom;
|
||||||
this.messageActiveDom = MessageUserStore.messageActiveDom;
|
this.messageError = MessageUserStore.error;
|
||||||
this.messageError = MessageUserStore.messageError;
|
|
||||||
|
|
||||||
this.fullScreenMode = MessageUserStore.messageFullScreenMode;
|
this.fullScreenMode = MessageUserStore.fullScreen;
|
||||||
|
|
||||||
this.messageListOfThreadsLoading = ko.observable(false).extend({ rateLimit: 1 });
|
this.messageListOfThreadsLoading = ko.observable(false).extend({ rateLimit: 1 });
|
||||||
this.highlightUnselectedAttachments = ko.observable(false).extend({ falseTimeout: 2000 });
|
this.highlightUnselectedAttachments = ko.observable(false).extend({ falseTimeout: 2000 });
|
||||||
|
@ -148,7 +145,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
messageVisibility: () => !MessageUserStore.messageLoading() && !!currentMessage(),
|
messageVisibility: () => !MessageUserStore.loading() && !!currentMessage(),
|
||||||
|
|
||||||
canBeRepliedOrForwarded: () => !this.isDraftFolder() && this.messageVisibility(),
|
canBeRepliedOrForwarded: () => !this.isDraftFolder() && this.messageVisibility(),
|
||||||
|
|
||||||
|
@ -177,7 +174,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
pgpSupported: () => currentMessage() && PgpUserStore.isSupported(),
|
pgpSupported: () => currentMessage() && PgpUserStore.isSupported(),
|
||||||
|
|
||||||
messageListOrViewLoading:
|
messageListOrViewLoading:
|
||||||
() => MessageUserStore.listIsLoading() | MessageUserStore.messageLoading()
|
() => MessagelistUserStore.isLoading() | MessageUserStore.loading()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addSubscribables({
|
this.addSubscribables({
|
||||||
|
@ -187,7 +184,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
lastReplyAction_: value => Local.set(ClientSideKeyName.LastReplyAction, value),
|
lastReplyAction_: value => Local.set(ClientSideKeyName.LastReplyAction, value),
|
||||||
|
|
||||||
message: message => {
|
message: message => {
|
||||||
this.messageActiveDom(null);
|
MessageUserStore.activeDom(null);
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
this.showAttachmentControls(false);
|
this.showAttachmentControls(false);
|
||||||
|
@ -206,7 +203,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
this.viewFromDkimData(message.fromDkimData());
|
this.viewFromDkimData(message.fromDkimData());
|
||||||
this.viewToShort(message.toToLine(true, true));
|
this.viewToShort(message.toToLine(true, true));
|
||||||
} else {
|
} else {
|
||||||
MessageUserStore.selectorMessageSelected(null);
|
MessagelistUserStore.selectedMessage(null);
|
||||||
|
|
||||||
this.viewHash = '';
|
this.viewHash = '';
|
||||||
|
|
||||||
|
@ -272,6 +269,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
replyOrforward(sType) {
|
replyOrforward(sType) {
|
||||||
|
this.lastReplyAction(sType);
|
||||||
showMessageComposer([sType, currentMessage()]);
|
showMessageComposer([sType, currentMessage()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +321,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
|
|
||||||
if (eqs(event, '.messageItemHeader .subjectParent .flagParent')) {
|
if (eqs(event, '.messageItemHeader .subjectParent .flagParent')) {
|
||||||
const message = currentMessage();
|
const message = currentMessage();
|
||||||
message && rl.app.messageListAction(
|
message && MessagelistUserStore.setAction(
|
||||||
message.folder,
|
message.folder,
|
||||||
message.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
message.isFlagged() ? MessageSetAction.UnsetFlag : MessageSetAction.SetFlag,
|
||||||
[message]
|
[message]
|
||||||
|
@ -551,7 +549,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
printableCheckedMessageCount() {
|
printableCheckedMessageCount() {
|
||||||
const cnt = MessageUserStore.listCheckedOrSelectedUidsWithSubMails().length;
|
const cnt = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails().length;
|
||||||
return 0 < cnt ? (100 > cnt ? cnt : '99+') : '';
|
return 0 < cnt ? (100 > cnt ? cnt : '99+') : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,7 +573,7 @@ export class MailMessageView extends AbstractViewRight {
|
||||||
|
|
||||||
MessageFlagsCache.store(oMessage);
|
MessageFlagsCache.store(oMessage);
|
||||||
|
|
||||||
MessageUserStore.reloadFlagsAndCachedMessage();
|
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,12 +72,12 @@ export class SystemDropDownUserView extends AbstractViewRight {
|
||||||
// MessageUserStore.setMessage();
|
// MessageUserStore.setMessage();
|
||||||
// MessageUserStore.purgeMessageBodyCache();
|
// MessageUserStore.purgeMessageBodyCache();
|
||||||
// MessageUserStore.hideMessageBodies();
|
// MessageUserStore.hideMessageBodies();
|
||||||
MessageUserStore.list([]);
|
MessagelistUserStore([]);
|
||||||
// FolderUserStore.folderList([]);
|
// FolderUserStore.folderList([]);
|
||||||
Remote.foldersReload(value => {
|
loadFolders(value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
// 4. Change to INBOX = reload MessageList
|
// 4. Change to INBOX = reload MessageList
|
||||||
// MessageUserStore.setMessageList();
|
// MessagelistUserStore.setMessageList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AccountUserStore.loading(false);
|
AccountUserStore.loading(false);
|
||||||
|
@ -126,7 +126,7 @@ export class SystemDropDownUserView extends AbstractViewRight {
|
||||||
onBuild() {
|
onBuild() {
|
||||||
shortcuts.add('m,contextmenu', '', [Scope.MessageList, Scope.MessageView, Scope.Settings], () => {
|
shortcuts.add('m,contextmenu', '', [Scope.MessageList, Scope.MessageView, Scope.Settings], () => {
|
||||||
if (!this.viewModelDom.hidden) {
|
if (!this.viewModelDom.hidden) {
|
||||||
MessageUserStore.messageFullScreenMode(false);
|
MessageUserStore.fullScreen(false);
|
||||||
this.accountMenuDropdownTrigger(true);
|
this.accountMenuDropdownTrigger(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue