diff --git a/dev/App/User.js b/dev/App/User.js
index 0c3093beb..7101ab3be 100644
--- a/dev/App/User.js
+++ b/dev/App/User.js
@@ -831,24 +831,105 @@
}
};
- AppUser.prototype.setMessageSeen = function (oMessage)
+ /**
+ * @param {string} sFolderFullNameRaw
+ * @param {string|bool} mUid
+ * @param {number} iSetAction
+ * @param {Array=} aMessages = null
+ */
+ AppUser.prototype.messageListAction = function (sFolderFullNameRaw, mUid, iSetAction, aMessages)
{
- if (oMessage.unseen())
+ var
+ bRoot = false,
+ aAllUids = [],
+ aRootUids = [],
+ oFolder = null,
+ iAlreadyUnread = 0
+ ;
+
+ if (Utils.isUnd(aMessages))
{
- oMessage.unseen(false);
-
- var oFolder = Cache.getFolderFromCacheList(oMessage.folderFullNameRaw);
- if (oFolder)
- {
- oFolder.messageCountUnread(0 <= oFolder.messageCountUnread() - 1 ?
- oFolder.messageCountUnread() - 1 : 0);
- }
-
- Cache.storeMessageFlagsToCache(oMessage);
- this.reloadFlagsCurrentMessageListAndMessageFromCache();
+ aMessages = MessageStore.messageListChecked();
}
- Remote.messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true);
+ if (true === mUid)
+ {
+ bRoot = true;
+ }
+ else if (aMessages && aMessages[0] && mUid &&
+ sFolderFullNameRaw === aMessages[0].uid && mUid === aMessages[0].uid)
+ {
+ bRoot = true;
+ }
+
+ _.each(aMessages, function (oMessage) {
+ aRootUids.push(oMessage.uid);
+ aAllUids = _.union(aAllUids, oMessage.threads(), [oMessage.uid]);
+ });
+
+ aAllUids = _.uniq(aAllUids);
+ aRootUids = _.uniq(aRootUids);
+ aRootUids = aAllUids; // always all
+
+ if ('' !== sFolderFullNameRaw && 0 < aAllUids.length)
+ {
+ switch (iSetAction) {
+ case Enums.MessageSetAction.SetSeen:
+
+ _.each(bRoot ? aAllUids : aRootUids, function (sSubUid) {
+ iAlreadyUnread += Cache.storeMessageFlagsToCacheBySetAction(
+ sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder)
+ {
+ oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread);
+ }
+
+ Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, bRoot ? aAllUids : aRootUids, true);
+ break;
+
+ case Enums.MessageSetAction.UnsetSeen:
+
+ _.each(aRootUids, function (sSubUid) {
+ iAlreadyUnread += Cache.storeMessageFlagsToCacheBySetAction(
+ sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder)
+ {
+ oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aRootUids.length);
+ }
+
+ Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aRootUids, false);
+ break;
+
+ case Enums.MessageSetAction.SetFlag:
+
+ _.each(aRootUids, function (sSubUid) {
+ Cache.storeMessageFlagsToCacheBySetAction(
+ sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aRootUids, true);
+ break;
+
+ case Enums.MessageSetAction.UnsetFlag:
+
+ _.each(bRoot ? aAllUids : aRootUids, function (sSubUid) {
+ Cache.storeMessageFlagsToCacheBySetAction(
+ sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, bRoot ? aAllUids : aRootUids, false);
+ break;
+ }
+
+ this.reloadFlagsCurrentMessageListAndMessageFromCache();
+ MessageStore.message.viewTrigger(!MessageStore.message.viewTrigger());
+ }
};
AppUser.prototype.googleConnect = function ()
diff --git a/dev/Common/Cache.js b/dev/Common/Cache.js
index e83773b65..d9f38ef3f 100644
--- a/dev/Common/Cache.js
+++ b/dev/Common/Cache.js
@@ -301,7 +301,8 @@
{
var
self = this,
- aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, oMessage.uid),
+ sUid = oMessage.uid,
+ aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, sUid),
mUnseenSubUid = null,
mFlaggedSubUid = null
;
@@ -318,13 +319,19 @@
if (0 < oMessage.threads().length)
{
- mUnseenSubUid = _.find(oMessage.threads(), function (iSubUid) {
- var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
+ mUnseenSubUid = _.find(oMessage.threads(), function (sSubUid) {
+ if (sUid === sSubUid){
+ return false;
+ }
+ var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, sSubUid);
return aFlags && 0 < aFlags.length && !!aFlags[0];
});
- mFlaggedSubUid = _.find(oMessage.threads(), function (iSubUid) {
- var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
+ mFlaggedSubUid = _.find(oMessage.threads(), function (sSubUid) {
+ if (sUid === sSubUid){
+ return false;
+ }
+ var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, sSubUid);
return aFlags && 0 < aFlags.length && !!aFlags[1];
});
@@ -349,6 +356,7 @@
);
}
};
+
/**
* @param {string} sFolder
* @param {string} sUid
@@ -362,6 +370,43 @@
}
};
+ /**
+ * @param {string} sFolder
+ * @param {string} sUid
+ * @param {number} iSetAction
+ */
+ CacheUserStorage.prototype.storeMessageFlagsToCacheBySetAction = function (sFolder, sUid, iSetAction)
+ {
+ var iUnread = 0, aFlags = this.getMessageFlagsFromCache(sFolder, sUid);
+ if (Utils.isArray(aFlags) && 0 < aFlags.length)
+ {
+ if (aFlags[0])
+ {
+ iUnread = 1;
+ }
+
+ switch (iSetAction)
+ {
+ case Enums.MessageSetAction.SetSeen:
+ aFlags[0] = false;
+ break;
+ case Enums.MessageSetAction.UnsetSeen:
+ aFlags[0] = true;
+ break;
+ case Enums.MessageSetAction.SetFlag:
+ aFlags[1] = true;
+ break;
+ case Enums.MessageSetAction.UnsetFlag:
+ aFlags[1] = false;
+ break;
+ }
+
+ this.setMessageFlagsToCache(sFolder, sUid, aFlags);
+ }
+
+ return iUnread;
+ };
+
module.exports = new CacheUserStorage();
}());
\ No newline at end of file
diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js
index 3c86b0d7b..7aa53f4ab 100644
--- a/dev/Common/Selector.js
+++ b/dev/Common/Selector.js
@@ -17,12 +17,13 @@
* @constructor
* @param {koProperty} oKoList
* @param {koProperty} oKoSelectedItem
+ * @param {koProperty} oKoFocusedItem
* @param {string} sItemSelector
* @param {string} sItemSelectedSelector
* @param {string} sItemCheckedSelector
* @param {string} sItemFocusedSelector
*/
- function Selector(oKoList, oKoSelectedItem,
+ function Selector(oKoList, oKoSelectedItem, oKoFocusedItem,
sItemSelector, sItemSelectedSelector, sItemCheckedSelector, sItemFocusedSelector)
{
this.list = oKoList;
@@ -37,8 +38,8 @@
return 0 < this.listChecked().length;
}, this);
- this.focusedItem = ko.observable(null);
- this.selectedItem = oKoSelectedItem;
+ this.focusedItem = oKoFocusedItem || ko.observable(null);
+ this.selectedItem = oKoSelectedItem || ko.observable(null);
this.selectedItemUseCallback = true;
this.itemSelectedThrottle = _.debounce(_.bind(this.itemSelected, this), 300);
diff --git a/dev/Model/Message.js b/dev/Model/Message.js
index e684aa06b..611032989 100644
--- a/dev/Model/Message.js
+++ b/dev/Model/Message.js
@@ -133,18 +133,13 @@
this.sInReplyTo = '';
this.sReferences = '';
- this.parentUid = ko.observable(0);
- this.threads = ko.observableArray([]);
- this.threadsLen = ko.observable(0);
this.hasUnseenSubMessage = ko.observable(false);
this.hasFlaggedSubMessage = ko.observable(false);
- this.lastInCollapsedThread = ko.observable(false);
- this.lastInCollapsedThreadLoading = ko.observable(false);
+ this.threads = ko.observableArray([]);
- this.threadsLenResult = ko.computed(function () {
- var iCount = this.threadsLen();
- return 0 === this.parentUid() && 0 < iCount ? iCount + 1 : '';
+ this.threadsLen = ko.computed(function () {
+ return this.threads().length;
}, this);
this.isImportant = ko.computed(function () {
@@ -152,7 +147,7 @@
}, this);
this.regDisposables([this.attachmentIconClass, this.fullFormatDateValue,
- this.threadsLenResult, this.isImportant]);
+ this.threadsLen, this.isImportant]);
}
_.extend(MessageModel.prototype, AbstractModel.prototype);
@@ -349,14 +344,10 @@
this.sInReplyTo = '';
this.sReferences = '';
- this.parentUid(0);
this.threads([]);
- this.threadsLen(0);
+
this.hasUnseenSubMessage(false);
this.hasFlaggedSubMessage(false);
-
- this.lastInCollapsedThread(false);
- this.lastInCollapsedThreadLoading(false);
};
/**
@@ -435,9 +426,7 @@
this.toEmailsString(MessageModel.emailsToLine(this.to, true));
this.toClearEmailsString(MessageModel.emailsToLineClear(this.to));
- this.parentUid(Utils.pInt(oJsonMessage.ParentThread));
this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []);
- this.threadsLen(Utils.pInt(oJsonMessage.ThreadsLen));
this.initFlagsByJson(oJsonMessage);
this.computeSenderEmail();
@@ -685,11 +674,7 @@
{
aResult.push('emptySubject');
}
- if (0 < this.parentUid())
- {
- aResult.push('hasParentMessage');
- }
- if (0 < this.threadsLen() && 0 === this.parentUid())
+ if (1 < this.threadsLen())
{
aResult.push('hasChildrenMessage');
}
@@ -994,9 +979,7 @@
this.sInReplyTo = '';
this.sReferences = '';
- this.parentUid(oMessage.parentUid());
this.threads(oMessage.threads());
- this.threadsLen(oMessage.threadsLen());
this.computeSenderEmail();
diff --git a/dev/Remote/User/Ajax.js b/dev/Remote/User/Ajax.js
index 2819f569c..e76ff4e22 100644
--- a/dev/Remote/User/Ajax.js
+++ b/dev/Remote/User/Ajax.js
@@ -16,7 +16,6 @@
AppStore = require('Stores/User/App'),
SettingsStore = require('Stores/User/Settings'),
- MessageStore = require('Stores/User/Message'),
AbstractAjaxRemote = require('Remote/AbstractAjax')
;
@@ -349,7 +348,7 @@
sFolderHash,
Cache.getFolderInboxName() === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '',
AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0',
- AppStore.threadsAllowed() && sFolderFullNameRaw === MessageStore.messageListThreadFolder() ? MessageStore.messageListThreadUids().join(',') : ''
+ ''
].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']);
}
else
@@ -361,7 +360,6 @@
'Search': sSearch,
'UidNext': Cache.getFolderInboxName() === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : '',
'UseThreads': AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0',
- 'ExpandedThreadUid': AppStore.threadsAllowed() && sFolderFullNameRaw === MessageStore.messageListThreadFolder() ? MessageStore.messageListThreadUids().join(',') : ''
}, '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, '', bSilent ? [] : ['MessageList']);
}
};
@@ -404,6 +402,35 @@
return false;
};
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {number} iUid
+ * @return {boolean}
+ */
+ RemoteUserStorage.prototype.messageThreadsFromCache = function (fCallback, sFolderFullNameRaw, iUid)
+ {
+ sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
+ iUid = Utils.pInt(iUid);
+
+ if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid)
+ {
+ var sFolderHash = Cache.getFolderHash(sFolderFullNameRaw);
+ if (sFolderHash)
+ {
+ this.defaultRequest(fCallback, 'MessageThreadsFromCache', {
+ 'Folder': sFolderFullNameRaw,
+ 'FolderHash': sFolderHash,
+ 'Uid': iUid
+ });
+
+ return true;
+ }
+ }
+
+ return false;
+ };
+
/**
* @param {?Function} fCallback
* @param {Array} aExternals
diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js
index 7885eceea..8a505c4d0 100644
--- a/dev/Stores/User/Message.js
+++ b/dev/Stores/User/Message.js
@@ -21,9 +21,12 @@
Cache = require('Common/Cache'),
+ AppStore = require('Stores/User/App'),
FolderStore = require('Stores/User/Folder'),
SettingsStore = require('Stores/User/Settings'),
+ Remote = require('Remote/User/Ajax'),
+
MessageModel = require('Model/Message')
;
@@ -41,9 +44,6 @@
this.messageListPage = ko.observable(1);
this.messageListError = ko.observable('');
- this.messageListThreadFolder = ko.observable('');
- this.messageListThreadUids = ko.observableArray([]);
-
this.messageListEndFolder = ko.observable('');
this.messageListEndSearch = ko.observable('');
this.messageListEndPage = ko.observable(1);
@@ -52,14 +52,29 @@
this.messageListIsNotCompleted = ko.observable(false);
this.messageListCompleteLoadingThrottle = ko.observable(false).extend({'throttle': 200});
+ this.messageListDisableAutoSelect = ko.observable(false).extend({'falseTimeout': 500});
+
// message viewer
this.message = ko.observable(null);
- this.currentMessage = ko.observable(null);
+
+ this.selectorMessageSelected = ko.observable(null);
+ this.selectorMessageFocused = ko.observable(null);
this.message.focused = ko.observable(false);
+ this.message.viewTrigger = ko.observable(false);
+
+ this.messageLastThreadUidsData = ko.observable(null);
+
this.messageError = ko.observable('');
- this.messageLoading = ko.observable(false);
+
+ this.messageCurrentLoading = ko.observable(false);
+ this.messageThreadLoading = ko.observable(false);
+
+ this.messageLoading = ko.computed(function () {
+ return !!(this.messageCurrentLoading() || this.messageThreadLoading());
+ }, this);
+
this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
this.messageFullScreenMode = ko.observable(false);
@@ -67,46 +82,11 @@
this.messagesBodiesDom = ko.observable(null);
this.messageActiveDom = ko.observable(null);
- this.messageListChecked = ko.computed(function () {
- return _.filter(this.messageList(), function (oItem) {
- return oItem.checked();
- });
- }, this).extend({'rateLimit': 0});
-
- this.hasCheckedMessages = ko.computed(function () {
- return 0 < this.messageListChecked().length;
- }, this).extend({'rateLimit': 0});
-
- this.messageListCheckedOrSelected = ko.computed(function () {
-
- var
- aChecked = this.messageListChecked(),
- oSelectedMessage = this.currentMessage()
- ;
-
- return _.union(aChecked, oSelectedMessage ? [oSelectedMessage] : []);
-
- }, this);
-
- this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(function () {
- var aList = [];
- _.each(this.messageListCheckedOrSelected(), function (oMessage) {
- if (oMessage)
- {
- aList.push(oMessage.uid);
- if (0 < oMessage.threadsLen() && 0 === oMessage.parentUid() && oMessage.lastInCollapsedThread())
- {
- aList = _.union(aList, oMessage.threads());
- }
- }
- });
- return aList;
- }, this);
-
-
this.computers();
this.subscribers();
+ this.onMessageResponse = _.bind(this.onMessageResponse, this);
+
this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, 1000 * 30);
}
@@ -143,14 +123,46 @@
this.isMessageSelected = ko.computed(function () {
return null !== this.message();
}, this);
+
+ this.messageListChecked = ko.computed(function () {
+ return _.filter(this.messageList(), function (oItem) {
+ return oItem.checked();
+ });
+ }, this).extend({'rateLimit': 0});
+
+ this.hasCheckedMessages = ko.computed(function () {
+ return 0 < this.messageListChecked().length;
+ }, this).extend({'rateLimit': 0});
+
+ this.messageListCheckedOrSelected = ko.computed(function () {
+
+ var
+ aChecked = this.messageListChecked(),
+ oSelectedMessage = this.selectorMessageSelected()
+ ;
+
+ return _.union(aChecked, oSelectedMessage ? [oSelectedMessage] : []);
+
+ }, this);
+
+ this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(function () {
+ var aList = [];
+ _.each(this.messageListCheckedOrSelected(), function (oMessage) {
+ if (oMessage)
+ {
+ aList.push(oMessage.uid);
+ if (1 < oMessage.threadsLen())
+ {
+ aList = _.union(aList, oMessage.threads());
+ }
+ }
+ });
+ return aList;
+ }, this);
};
MessageUserStore.prototype.subscribers = function ()
{
- this.messageListThreadFolder.subscribe(function () {
- this.messageListThreadUids([]);
- }, this);
-
this.messageListCompleteLoading.subscribe(function (bValue) {
this.messageListCompleteLoadingThrottle(bValue);
}, this);
@@ -421,24 +433,19 @@
if ($oList && 0 < $oList.length)
{
- _.delay(function () {
- $oList.each(function () {
- var $self = $(this), iH = $self.height();
- if (0 === iH || 150 < iH)
- {
- $self.addClass('rl-bq-switcher hidden-bq');
- $('')
- .insertBefore($self)
- .click(function () {
- $self.toggleClass('hidden-bq');
- Utils.windowResize();
- })
- .after('
')
- .before('
')
- ;
- }
- });
- }, 100);
+ $oList.each(function () {
+ var $self = $(this);
+ $self.addClass('rl-bq-switcher hidden-bq');
+ $('')
+ .insertBefore($self)
+ .click(function () {
+ $self.toggleClass('hidden-bq');
+ Utils.windowResize();
+ })
+ .after('
')
+ .before('
')
+ ;
+ });
}
}
};
@@ -446,6 +453,7 @@
MessageUserStore.prototype.setMessage = function (oData, bCached)
{
var
+ bNew = false,
bIsHtml = false,
bHasExternals = false,
bHasInternals = false,
@@ -456,143 +464,282 @@
bPgpSigned = false,
bPgpEncrypted = false,
oMessagesBodiesDom = this.messagesBodiesDom(),
- oMessage = this.message()
+ oSelectedMessage = this.selectorMessageSelected(),
+ oMessage = this.message(),
+ aThreads = []
;
if (oData && oMessage && oData.Result && 'Object/Message' === oData.Result['@Object'] &&
- oMessage.folderFullNameRaw === oData.Result.Folder && oMessage.uid === oData.Result.Uid)
+ oMessage.folderFullNameRaw === oData.Result.Folder)
{
- this.messageError('');
-
- oMessage.initUpdateByMessageJson(oData.Result);
- Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
-
- if (!bCached)
+ aThreads = oMessage.threads();
+ if (oMessage.uid !== oData.Result.Uid && 1 < aThreads.length &&
+ -1 < Utils.inArray(oData.Result.Uid, aThreads))
{
- oMessage.initFlagsByJson(oData.Result);
+ oMessage = MessageModel.newInstanceFromJson(oData.Result);
+ if (oMessage)
+ {
+ oMessage.threads(aThreads);
+ Cache.initMessageFlagsFromCache(oMessage);
+
+ this.message(this.staticMessage.populateByMessageListItem(oMessage));
+ oMessage = this.message(),
+
+ bNew = true;
+ }
}
- oMessagesBodiesDom = oMessagesBodiesDom && oMessagesBodiesDom[0] ? oMessagesBodiesDom : null;
- if (oMessagesBodiesDom)
+ if (oMessage && oMessage.uid === oData.Result.Uid)
{
- sId = 'rl-mgs-' + oMessage.hash.replace(/[^a-zA-Z0-9]/g, '');
- oTextBody = oMessagesBodiesDom.find('#' + sId);
- if (!oTextBody || !oTextBody[0])
+ this.messageError('');
+
+ oMessage.initUpdateByMessageJson(oData.Result);
+ Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
+
+ if (!bCached)
{
- bHasExternals = !!oData.Result.HasExternals;
- bHasInternals = !!oData.Result.HasInternals;
+ oMessage.initFlagsByJson(oData.Result);
+ }
- oBody = $('
').hide().addClass('rl-cache-class');
- oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
-
- if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html)
+ oMessagesBodiesDom = oMessagesBodiesDom && oMessagesBodiesDom[0] ? oMessagesBodiesDom : null;
+ if (oMessagesBodiesDom)
+ {
+ sId = 'rl-mgs-' + oMessage.hash.replace(/[^a-zA-Z0-9]/g, '');
+ oTextBody = oMessagesBodiesDom.find('#' + sId);
+ if (!oTextBody || !oTextBody[0])
{
- bIsHtml = true;
- sResultHtml = oData.Result.Html.toString();
- }
- else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain)
- {
- bIsHtml = false;
- sResultHtml = Utils.plainToHtml(oData.Result.Plain.toString(), false);
+ bHasExternals = !!oData.Result.HasExternals;
+ bHasInternals = !!oData.Result.HasInternals;
- if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && require('Stores/User/Pgp').capaOpenPGP())
+ oBody = $('').hide().addClass('rl-cache-class');
+ oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
+
+ if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html)
{
- oMessage.plainRaw = Utils.pString(oData.Result.Plain);
-
- bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oMessage.plainRaw);
- if (!bPgpEncrypted)
- {
- bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) &&
- /-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw);
- }
-
- Globals.$div.empty();
- if (bPgpSigned && oMessage.isPgpSigned())
- {
- sResultHtml =
- Globals.$div.append(
- $('').text(oMessage.plainRaw)
- ).html()
- ;
- }
- else if (bPgpEncrypted && oMessage.isPgpEncrypted())
- {
- sResultHtml =
- Globals.$div.append(
- $('').text(oMessage.plainRaw)
- ).html()
- ;
- }
-
- Globals.$div.empty();
-
- oMessage.isPgpSigned(bPgpSigned);
- oMessage.isPgpEncrypted(bPgpEncrypted);
+ bIsHtml = true;
+ sResultHtml = oData.Result.Html.toString();
}
+ else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain)
+ {
+ bIsHtml = false;
+ sResultHtml = Utils.plainToHtml(oData.Result.Plain.toString(), false);
+
+ if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && require('Stores/User/Pgp').capaOpenPGP())
+ {
+ oMessage.plainRaw = Utils.pString(oData.Result.Plain);
+
+ bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oMessage.plainRaw);
+ if (!bPgpEncrypted)
+ {
+ bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) &&
+ /-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw);
+ }
+
+ Globals.$div.empty();
+ if (bPgpSigned && oMessage.isPgpSigned())
+ {
+ sResultHtml =
+ Globals.$div.append(
+ $('').text(oMessage.plainRaw)
+ ).html()
+ ;
+ }
+ else if (bPgpEncrypted && oMessage.isPgpEncrypted())
+ {
+ sResultHtml =
+ Globals.$div.append(
+ $('').text(oMessage.plainRaw)
+ ).html()
+ ;
+ }
+
+ Globals.$div.empty();
+
+ oMessage.isPgpSigned(bPgpSigned);
+ oMessage.isPgpEncrypted(bPgpEncrypted);
+ }
+ }
+ else
+ {
+ bIsHtml = false;
+ }
+
+ oBody
+ .html(Utils.findEmailAndLinks(sResultHtml))
+ .addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain'))
+ ;
+
+ oMessage.isHtml(!!bIsHtml);
+ oMessage.hasImages(!!bHasExternals);
+ oMessage.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
+ oMessage.pgpSignedVerifyUser('');
+
+ oMessage.body = oBody;
+ if (oMessage.body)
+ {
+ oMessagesBodiesDom.append(oMessage.body);
+ }
+
+ oMessage.storeDataToDom();
+
+ if (bHasInternals)
+ {
+ oMessage.showInternalImages(true);
+ }
+
+ if (oMessage.hasImages() && SettingsStore.showImages())
+ {
+ oMessage.showExternalImages(true);
+ }
+
+ this.purgeMessageBodyCacheThrottle();
}
else
{
- bIsHtml = false;
+ oMessage.body = oTextBody;
+ if (oMessage.body)
+ {
+ oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
+ oMessage.fetchDataToDom();
+ }
}
- oBody
- .html(Utils.findEmailAndLinks(sResultHtml))
- .addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain'))
- ;
+ this.messageActiveDom(oMessage.body);
- oMessage.isHtml(!!bIsHtml);
- oMessage.hasImages(!!bHasExternals);
- oMessage.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
- oMessage.pgpSignedVerifyUser('');
+ this.hideMessageBodies();
- oMessage.body = oBody;
- if (oMessage.body)
+ if (oBody)
{
- oMessagesBodiesDom.append(oMessage.body);
+ this.initBlockquoteSwitcher(oBody);
}
- oMessage.storeDataToDom();
-
- if (bHasInternals)
- {
- oMessage.showInternalImages(true);
- }
-
- if (oMessage.hasImages() && SettingsStore.showImages())
- {
- oMessage.showExternalImages(true);
- }
-
- this.purgeMessageBodyCacheThrottle();
+ oMessage.body.show();
}
- else
+
+ Cache.initMessageFlagsFromCache(oMessage);
+ if (oMessage.unseen() || oMessage.hasUnseenSubMessage())
{
- oMessage.body = oTextBody;
- if (oMessage.body)
- {
- oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
- oMessage.fetchDataToDom();
- }
+ require('App/User').messageListAction(oMessage.folderFullNameRaw,
+ oMessage.uid, Enums.MessageSetAction.SetSeen, [oMessage]);
}
- this.messageActiveDom(oMessage.body);
-
- this.hideMessageBodies();
- oMessage.body.show();
-
- if (oBody)
+ if (bNew)
{
- this.initBlockquoteSwitcher(oBody);
+ oMessage = this.message();
+
+ if (oSelectedMessage && oMessage && (
+ oMessage.folderFullNameRaw !== oSelectedMessage.folderFullNameRaw ||
+ oMessage.uid !== oSelectedMessage.uid
+ ))
+ {
+ this.selectorMessageSelected(null);
+ if (1 === this.messageList().length)
+ {
+ this.selectorMessageFocused(null);
+ }
+ }
+ else if (!oSelectedMessage && oMessage)
+ {
+ oSelectedMessage = _.find(this.messageList(), function (oSubMessage) {
+ return oSubMessage &&
+ oSubMessage.folderFullNameRaw === oMessage.folderFullNameRaw &&
+ oSubMessage.uid === oMessage.uid;
+ });
+
+ if (oSelectedMessage)
+ {
+ this.selectorMessageSelected(oSelectedMessage);
+ this.selectorMessageFocused(oSelectedMessage);
+ }
+ }
+
}
+
+ Utils.windowResize();
}
+ }
+ };
- Cache.initMessageFlagsFromCache(oMessage);
- if (oMessage.unseen())
+ MessageUserStore.prototype.selectMessage = function (oMessage)
+ {
+ if (oMessage)
+ {
+ this.message(this.staticMessage.populateByMessageListItem(oMessage));
+
+ this.populateMessageBody(this.message());
+
+ if (Enums.Layout.NoPreview === SettingsStore.layout())
{
- require('App/User').setMessageSeen(oMessage);
+ kn.setHash(Links.messagePreview(), true);
+ this.message.focused(true);
}
+ }
+ else
+ {
+ this.message(null);
+ }
+ };
- Utils.windowResize();
+ MessageUserStore.prototype.selectThreadMessage = function (sFolder, sUid)
+ {
+ if (Remote.message(this.onMessageResponse, sFolder, sUid))
+ {
+ this.messageThreadLoading(true);
+ }
+ else
+ {
+ Utils.log('Error: Unknown message request: ' + sFolder + ' ~ ' + sUid + ' [e-102]');
+ }
+
+ if (Enums.Layout.NoPreview === SettingsStore.layout())
+ {
+ kn.setHash(Links.messagePreview(), true);
+ this.message.focused(true);
+ }
+ };
+
+ MessageUserStore.prototype.populateMessageBody = function (oMessage)
+ {
+ if (oMessage)
+ {
+ if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid))
+ {
+ this.messageCurrentLoading(true);
+ }
+ else
+ {
+ Utils.log('Error: Unknown message request: ' + oMessage.folderFullNameRaw + ' ~ ' + oMessage.uid + ' [e-101]');
+ }
+ }
+ };
+
+ /**
+ * @param {string} sResult
+ * @param {AjaxJsonDefaultResponse} oData
+ * @param {boolean} bCached
+ */
+ MessageUserStore.prototype.onMessageResponse = function (sResult, oData, bCached)
+ {
+ this.hideMessageBodies();
+
+ this.messageCurrentLoading(false);
+ this.messageThreadLoading(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.setMessage(oData, bCached);
+ }
+ else if (Enums.StorageResultType.Unload === sResult)
+ {
+ this.message(null);
+ this.messageError('');
+ }
+ else if (Enums.StorageResultType.Abort !== sResult)
+ {
+ this.message(null);
+ this.messageError((oData && oData.ErrorCode ?
+ Translator.getNotification(oData.ErrorCode) :
+ Translator.getNotification(Enums.Notification.UnknownError)));
}
};
@@ -613,7 +760,7 @@
oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
{
var
- mLastCollapsedThreadUids = null,
+ self = this,
iIndex = 0,
iLen = 0,
iCount = 0,
@@ -630,11 +777,6 @@
iCount = Utils.pInt(oData.Result.MessageResultCount);
iOffset = Utils.pInt(oData.Result.Offset);
- if (Utils.isNonEmptyArray(oData.Result.LastCollapsedThreadUids))
- {
- mLastCollapsedThreadUids = oData.Result.LastCollapsedThreadUids;
- }
-
oFolder = Cache.getFolderFromCacheList(
Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
@@ -692,9 +834,6 @@
Cache.storeMessageFlagsToCache(oMessage);
}
- oMessage.lastInCollapsedThreadLoading(false);
- oMessage.lastInCollapsedThread(mLastCollapsedThreadUids && -1 < Utils.inArray(Utils.pInt(oMessage.uid), mLastCollapsedThreadUids) ? true : false);
-
aList.push(oMessage);
}
}
@@ -708,11 +847,33 @@
this.messageListEndSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
this.messageListEndPage(this.messageListPage());
+ this.messageListDisableAutoSelect(true);
+
this.messageList(aList);
this.messageListIsNotCompleted(false);
Cache.clearNewMessageCache();
+ if (AppStore.threadsAllowed() && SettingsStore.useThreads())
+ {
+ oMessage = this.message();
+ if (oMessage)
+ {
+ Remote.messageThreadsFromCache(function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.ThreadUids)
+ {
+ self.messageLastThreadUidsData({
+ 'Folder': oData.Result.Folder,
+ 'Uid': oData.Result.Uid,
+ 'Uids': oData.Result.ThreadUids
+ });
+ }
+
+ }, oMessage.folderFullNameRaw, oMessage.uid);
+ }
+ }
+
if (oFolder && (bCached || bUnreadCountChange || SettingsStore.useThreads()))
{
require('App/User').folderInformation(oFolder.fullNameRaw, aList);
diff --git a/dev/Styles/MessageView.less b/dev/Styles/MessageView.less
index dfb68c43a..0fb9c26a0 100644
--- a/dev/Styles/MessageView.less
+++ b/dev/Styles/MessageView.less
@@ -110,7 +110,6 @@ html.rl-no-preview-pane {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
- margin-left: 3px;
}
.senderParent {
@@ -121,8 +120,25 @@ html.rl-no-preview-pane {
margin-top: 5px;
}
+ .flagParent {
+
+ cursor: pointer;
+ margin-right: 5px;
+
+ .flagOn {
+ color: orange;
+ }
+
+ .flagOff {
+ opacity: 0.5;
+ &:hover {
+ opacity: 1;
+ }
+ }
+ }
+
.informationShort {
- margin-left: 15px;
+ margin-left: 22px;
a {
.g-ui-link;
}
diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js
index 42844cfd3..cbe6863fb 100644
--- a/dev/View/Popup/Contacts.js
+++ b/dev/View/Popup/Contacts.js
@@ -208,7 +208,7 @@
});
}, this);
- this.selector = new Selector(this.contacts, this.currentContact,
+ this.selector = new Selector(this.contacts, this.currentContact, null,
'.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem',
'.e-contact-item.focused');
diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js
index 8111776e6..2ee73c4ff 100644
--- a/dev/View/User/MailBox/MessageList.js
+++ b/dev/View/User/MailBox/MessageList.js
@@ -52,8 +52,10 @@
this.message = MessageStore.message;
this.messageList = MessageStore.messageList;
+ this.messageListDisableAutoSelect = MessageStore.messageListDisableAutoSelect;
this.folderList = FolderStore.folderList;
- this.currentMessage = MessageStore.currentMessage;
+ this.selectorMessageSelected = MessageStore.selectorMessageSelected;
+ this.selectorMessageFocused = MessageStore.selectorMessageFocused;
this.isMessageSelected = MessageStore.isMessageSelected;
this.messageListSearch = MessageStore.messageListSearch;
this.messageListError = MessageStore.messageListError;
@@ -224,27 +226,12 @@
this.quotaTooltip = _.bind(this.quotaTooltip, this);
- this.selector = new Selector(this.messageList, this.currentMessage,
+ this.selector = new Selector(this.messageList, this.selectorMessageSelected, this.selectorMessageFocused,
'.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage',
'.messageListItem.focused');
this.selector.on('onItemSelect', _.bind(function (oMessage) {
- if (oMessage)
- {
- MessageStore.message(MessageStore.staticMessage.populateByMessageListItem(oMessage));
-
- this.populateMessageBody(MessageStore.message());
-
- if (Enums.Layout.NoPreview === SettingsStore.layout())
- {
- kn.setHash(Links.messagePreview(), true);
- MessageStore.message.focused(true);
- }
- }
- else
- {
- MessageStore.message(null);
- }
+ MessageStore.selectMessage(oMessage);
}, this));
this.selector.on('onItemGetUid', function (oMessage) {
@@ -281,6 +268,11 @@
MessageListMailBoxUserView.prototype.useAutoSelect = function ()
{
+ if (this.messageListDisableAutoSelect())
+ {
+ return false;
+ }
+
if (/is:unseen/.test(this.mainMessageListSearch()))
{
return false;
@@ -353,129 +345,15 @@
return oEl;
};
- /**
- * @param {string} sResult
- * @param {AjaxJsonDefaultResponse} oData
- * @param {boolean} bCached
- */
- MessageListMailBoxUserView.prototype.onMessageResponse = function (sResult, oData, bCached)
- {
- MessageStore.hideMessageBodies();
- MessageStore.messageLoading(false);
-
- if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
- {
- MessageStore.setMessage(oData, bCached);
- }
- else if (Enums.StorageResultType.Unload === sResult)
- {
- MessageStore.message(null);
- MessageStore.messageError('');
- }
- else if (Enums.StorageResultType.Abort !== sResult)
- {
- MessageStore.message(null);
- MessageStore.messageError((oData && oData.ErrorCode ?
- Translator.getNotification(oData.ErrorCode) :
- Translator.getNotification(Enums.Notification.UnknownError)));
- }
- };
-
- MessageListMailBoxUserView.prototype.populateMessageBody = function (oMessage)
- {
- if (oMessage)
- {
- if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid))
- {
- MessageStore.messageLoading(true);
- }
- else
- {
- Utils.log('Error: Unknown message request: ' + oMessage.folderFullNameRaw + ' ~ ' + oMessage.uid + ' [e-101]');
- }
- }
- };
-
/**
* @param {string} sFolderFullNameRaw
+ * @param {string|bool} sUid
* @param {number} iSetAction
* @param {Array=} aMessages = null
*/
- MessageListMailBoxUserView.prototype.setAction = function (sFolderFullNameRaw, iSetAction, aMessages)
+ MessageListMailBoxUserView.prototype.setAction = function (sFolderFullNameRaw, mUid, iSetAction, aMessages)
{
- var
- aUids = [],
- oFolder = null,
- iAlreadyUnread = 0
- ;
-
- if (Utils.isUnd(aMessages))
- {
- aMessages = MessageStore.messageListChecked();
- }
-
- aUids = _.map(aMessages, function (oMessage) {
- return oMessage.uid;
- });
-
- if ('' !== sFolderFullNameRaw && 0 < aUids.length)
- {
- switch (iSetAction) {
- case Enums.MessageSetAction.SetSeen:
- _.each(aMessages, function (oMessage) {
- if (oMessage.unseen())
- {
- iAlreadyUnread++;
- }
-
- oMessage.unseen(false);
- Cache.storeMessageFlagsToCache(oMessage);
- });
-
- oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
- if (oFolder)
- {
- oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread);
- }
-
- Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, true);
- break;
- case Enums.MessageSetAction.UnsetSeen:
- _.each(aMessages, function (oMessage) {
- if (oMessage.unseen())
- {
- iAlreadyUnread++;
- }
-
- oMessage.unseen(true);
- Cache.storeMessageFlagsToCache(oMessage);
- });
-
- oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
- if (oFolder)
- {
- oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aUids.length);
- }
- Remote.messageSetSeen(Utils.emptyFunction, sFolderFullNameRaw, aUids, false);
- break;
- case Enums.MessageSetAction.SetFlag:
- _.each(aMessages, function (oMessage) {
- oMessage.flagged(true);
- Cache.storeMessageFlagsToCache(oMessage);
- });
- Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, true);
- break;
- case Enums.MessageSetAction.UnsetFlag:
- _.each(aMessages, function (oMessage) {
- oMessage.flagged(false);
- Cache.storeMessageFlagsToCache(oMessage);
- });
- Remote.messageSetFlagged(Utils.emptyFunction, sFolderFullNameRaw, aUids, false);
- break;
- }
-
- require('App/User').reloadFlagsCurrentMessageListAndMessageFromCache();
- }
+ require('App/User').messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages);
};
/**
@@ -532,8 +410,8 @@
MessageListMailBoxUserView.prototype.listSetSeen = function ()
{
- this.setAction(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen,
- MessageStore.messageListCheckedOrSelected());
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.SetSeen, MessageStore.messageListCheckedOrSelected());
};
MessageListMailBoxUserView.prototype.listSetAllSeen = function ()
@@ -543,20 +421,20 @@
MessageListMailBoxUserView.prototype.listUnsetSeen = function ()
{
- this.setAction(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetSeen,
- MessageStore.messageListCheckedOrSelected());
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.UnsetSeen, MessageStore.messageListCheckedOrSelected());
};
MessageListMailBoxUserView.prototype.listSetFlags = function ()
{
- this.setAction(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.SetFlag,
- MessageStore.messageListCheckedOrSelected());
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.SetFlag, MessageStore.messageListCheckedOrSelected());
};
MessageListMailBoxUserView.prototype.listUnsetFlags = function ()
{
- this.setAction(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.UnsetFlag,
- MessageStore.messageListCheckedOrSelected());
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.UnsetFlag, MessageStore.messageListCheckedOrSelected());
};
MessageListMailBoxUserView.prototype.flagMessages = function (oCurrentMessage)
@@ -577,12 +455,12 @@
if (0 < aCheckedUids.length && -1 < Utils.inArray(oCurrentMessage.uid, aCheckedUids))
{
- this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ?
+ this.setAction(oCurrentMessage.folderFullNameRaw, true, oCurrentMessage.flagged() ?
Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
}
else
{
- this.setAction(oCurrentMessage.folderFullNameRaw, oCurrentMessage.flagged() ?
+ this.setAction(oCurrentMessage.folderFullNameRaw, true, oCurrentMessage.flagged() ?
Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oCurrentMessage]);
}
}
@@ -603,12 +481,12 @@
if (Utils.isUnd(bFlag))
{
- this.setAction(aChecked[0].folderFullNameRaw,
+ this.setAction(aChecked[0].folderFullNameRaw, true,
aChecked.length === aFlagged.length ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
}
else
{
- this.setAction(aChecked[0].folderFullNameRaw,
+ this.setAction(aChecked[0].folderFullNameRaw, true,
!bFlag ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
}
}
@@ -629,12 +507,12 @@
if (Utils.isUnd(bSeen))
{
- this.setAction(aChecked[0].folderFullNameRaw,
+ this.setAction(aChecked[0].folderFullNameRaw, true,
0 < aUnseen.length ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked);
}
else
{
- this.setAction(aChecked[0].folderFullNameRaw,
+ this.setAction(aChecked[0].folderFullNameRaw, true,
bSeen ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked);
}
}
@@ -647,38 +525,6 @@
this.oContentVisible = $('.b-content', oDom);
this.oContentScrollable = $('.content', this.oContentVisible);
- this.oContentVisible.on('click', '.fullThreadHandle', function () {
- var
- aList = [],
- oMessage = ko.dataFor(this)
- ;
-
- if (oMessage && !oMessage.lastInCollapsedThreadLoading())
- {
- MessageStore.messageListThreadFolder(oMessage.folderFullNameRaw);
-
- aList = MessageStore.messageListThreadUids();
-
- if (oMessage.lastInCollapsedThread())
- {
- aList.push(0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid);
- }
- else
- {
- aList = _.without(aList, 0 < oMessage.parentUid() ? oMessage.parentUid() : oMessage.uid);
- }
-
- MessageStore.messageListThreadUids(_.uniq(aList));
-
- oMessage.lastInCollapsedThreadLoading(true);
- oMessage.lastInCollapsedThread(!oMessage.lastInCollapsedThread());
-
- require('App/User').reloadMessageList();
- }
-
- return false;
- });
-
this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.MessageList);
oDom
diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js
index f43b68aa2..58c78b704 100644
--- a/dev/View/User/MailBox/MessageView.js
+++ b/dev/View/User/MailBox/MessageView.js
@@ -58,11 +58,9 @@
this.pswp = null;
this.message = MessageStore.message;
- this.currentMessage = MessageStore.currentMessage;
this.messageListChecked = MessageStore.messageListChecked;
this.hasCheckedMessages = MessageStore.hasCheckedMessages;
this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails;
- this.messageLoading = MessageStore.messageLoading;
this.messageLoadingThrottle = MessageStore.messageLoadingThrottle;
this.messagesBodiesDom = MessageStore.messagesBodiesDom;
this.useThreads = SettingsStore.useThreads;
@@ -103,7 +101,7 @@
this.message.subscribe(function (oMessage) {
if (!oMessage)
{
- this.currentMessage(null);
+ MessageStore.selectorMessageSelected(null);
}
}, this);
@@ -130,47 +128,52 @@
}, this.messageVisibility);
this.deleteCommand = Utils.createCommand(this, function () {
- if (this.message())
+ var oMessage = this.message();
+ if (oMessage)
{
+ this.message(null);
require('App/User').deleteMessagesFromFolder(Enums.FolderType.Trash,
- this.message().folderFullNameRaw,
- [this.message().uid], true);
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
}
}, this.messageVisibility);
this.deleteWithoutMoveCommand = Utils.createCommand(this, function () {
- if (this.message())
+ var oMessage = this.message();
+ if (oMessage)
{
+ this.message(null);
require('App/User').deleteMessagesFromFolder(Enums.FolderType.Trash,
- FolderStore.currentFolderFullNameRaw(),
- [this.message().uid], false);
+ oMessage.folderFullNameRaw, [oMessage.uid], false);
}
}, this.messageVisibility);
this.archiveCommand = Utils.createCommand(this, function () {
- if (this.message())
+ var oMessage = this.message();
+ if (oMessage)
{
+ this.message(null);
require('App/User').deleteMessagesFromFolder(Enums.FolderType.Archive,
- this.message().folderFullNameRaw,
- [this.message().uid], true);
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
}
}, this.messageVisibility);
this.spamCommand = Utils.createCommand(this, function () {
- if (this.message())
+ var oMessage = this.message();
+ if (oMessage)
{
+ this.message(null);
require('App/User').deleteMessagesFromFolder(Enums.FolderType.Spam,
- this.message().folderFullNameRaw,
- [this.message().uid], true);
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
}
}, this.messageVisibility);
this.notSpamCommand = Utils.createCommand(this, function () {
- if (this.message())
+ var oMessage = this.message();
+ if (oMessage)
{
+ this.message(null);
require('App/User').deleteMessagesFromFolder(Enums.FolderType.NotSpam,
- this.message().folderFullNameRaw,
- [this.message().uid], true);
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
}
}, this.messageVisibility);
@@ -178,6 +181,8 @@
this.viewBodyTopValue = ko.observable(0);
+ this.viewFolder = '';
+ this.viewUid = '';
this.viewHash = '';
this.viewSubject = ko.observable('');
this.viewFromShort = ko.observable('');
@@ -197,7 +202,94 @@
this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic);
this.viewUserPicVisible = ko.observable(false);
this.viewIsImportant = ko.observable(false);
+ this.viewIsFlagged = ko.observable(false);
+// THREADS
+ this.viewThreads = ko.observableArray([]);
+ this.viewThreads.trigger = ko.observable(false);
+
+ MessageStore.messageLastThreadUidsData.subscribe(function (oData) {
+ if (oData && oData['Uids'])
+ {
+ oData['Uid'] = Utils.pString(oData['Uid']);
+ if (this.viewFolder === oData['Folder'] && this.viewUid === oData['Uid'])
+ {
+ this.viewThreads(oData['Uids']);
+ this.viewThreads.trigger(!this.viewThreads.trigger());
+ }
+
+ var oMessage = MessageStore.message();
+ if (oMessage && oMessage.folderFullNameRaw === oData['Folder'] && oMessage.uid === oData['Uid'])
+ {
+ oMessage.threads(oData['Uids']);
+ }
+
+ oMessage = _.find(MessageStore.messageList(), function (oMessage) {
+ return oMessage && oMessage.folderFullNameRaw === oData['Folder'] && oMessage.uid === oData['Uid'];
+ });
+
+ if (oMessage && oMessage.folderFullNameRaw === oData['Folder'] && oMessage.uid === oData['Uid'])
+ {
+ oMessage.threads(oData['Uids']);
+ }
+ }
+ }, this);
+
+ this.viewThreads.status = ko.computed(function () {
+
+ this.viewThreads.trigger();
+
+ var
+ iIndex = 0,
+ aResult = [false, '', '', '', ''],
+ aThreads = this.viewThreads.peek(),
+ iLen = aThreads.length
+ ;
+
+ if (1 < iLen)
+ {
+ iIndex = Utils.inArray(this.viewUid, aThreads);
+ if (-1 < iIndex)
+ {
+ aResult[0] = true;
+ aResult[1] = (iIndex + 1) + ' / ' + iLen;
+ aResult[2] = aThreads[iIndex];
+ aResult[3] = 0 < iIndex && aThreads[iIndex - 1] ? aThreads[iIndex - 1] : '';
+ aResult[4] = aThreads[iIndex + 1] ? aThreads[iIndex + 1] : '';
+ }
+ }
+
+ return aResult;
+
+ }, this).extend({'notify': 'always'});
+
+ this.viewThreadsControlVisibility = ko.computed(function () {
+ return !!this.viewThreads.status()[0];
+ }, this);
+
+ this.viewThreadsControlDesc = ko.computed(function () {
+ return this.viewThreads.status()[1];
+ }, this);
+
+ this.viewThreadsControlBackAllow = ko.computed(function () {
+ return '' !== this.viewThreads.status()[4] && !this.messageLoadingThrottle();
+ }, this);
+
+ this.viewThreadsControlForwardAllow = ko.computed(function () {
+ return '' !== this.viewThreads.status()[3] && !this.messageLoadingThrottle();
+ }, this);
+
+ this.threadBackCommand = Utils.createCommand(this, function () {
+ var aStatus = this.viewThreads.status();
+ this.openThreadMessage(aStatus[4]);
+ }, this.viewThreadsControlBackAllow);
+
+ this.threadForwardCommand = Utils.createCommand(this, function () {
+ var aStatus = this.viewThreads.status();
+ this.openThreadMessage(aStatus[3]);
+ }, this.viewThreadsControlForwardAllow);
+
+// PGP
this.viewPgpPassword = ko.observable('');
this.viewPgpSignedVerifyStatus = ko.computed(function () {
return this.message() ? this.message().pgpSignedVerifyStatus() : Enums.SignedVerifyStatus.None;
@@ -260,6 +352,8 @@
this.scrollMessageToTop();
}
+ this.viewFolder = oMessage.folderFullNameRaw;
+ this.viewUid = oMessage.uid;
this.viewHash = oMessage.hash;
this.viewSubject(oMessage.subject());
this.viewFromShort(oMessage.fromToLine(true, true));
@@ -277,6 +371,10 @@
this.viewViewLink(oMessage.viewLink());
this.viewDownloadLink(oMessage.downloadLink());
this.viewIsImportant(oMessage.isImportant());
+ this.viewIsFlagged(oMessage.flagged());
+
+ this.viewThreads(oMessage.threads());
+ this.viewThreads.trigger(!this.viewThreads.trigger());
sLastEmail = oMessage.fromAsSingleEmail();
Cache.getUserPic(sLastEmail, function (sPic, sEmail) {
@@ -294,12 +392,29 @@
}
else
{
+ this.viewFolder = '';
+ this.viewUid = '';
this.viewHash = '';
+
+ this.viewThreads([]);
+
this.scrollMessageToTop();
}
}, this);
+ this.message.viewTrigger.subscribe(function () {
+ var oMessage = this.message();
+ if (oMessage)
+ {
+ this.viewIsFlagged(oMessage.flagged());
+ }
+ else
+ {
+ this.viewIsFlagged(false);
+ }
+ }, this);
+
this.fullScreenMode.subscribe(function (bValue) {
if (bValue)
{
@@ -333,6 +448,24 @@
kn.extendAsViewModel(['View/User/MailBox/MessageView', 'View/App/MailBox/MessageView', 'MailBoxMessageViewViewModel'], MessageViewMailBoxUserView);
_.extend(MessageViewMailBoxUserView.prototype, AbstractView.prototype);
+ MessageViewMailBoxUserView.prototype.updateViewFlagsFromCache = function ()
+ {
+ var aFlags = this.getMessageFlagsFromCache(this.viewFolder, this.viewUid);
+ if (aFlags)
+ {
+ this.viewIsFlagged(!!aFlags[1]);
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.openThreadMessage = function (sUid)
+ {
+ var oMessage = this.message();
+ if (oMessage && sUid)
+ {
+ MessageStore.selectThreadMessage(oMessage.folderFullNameRaw, sUid);
+ }
+ };
+
MessageViewMailBoxUserView.prototype.isPgpActionVisible = function ()
{
return Enums.SignedVerifyStatus.Success !== this.viewPgpSignedVerifyStatus();
@@ -543,6 +676,9 @@
require('App/User').download(oAttachment.linkDownload());
}
})
+ .on('click', '.messageItemHeader .flagParent', function () {
+ self.flagViewMessage();
+ })
;
this.message.focused.subscribe(function (bValue) {
@@ -575,6 +711,19 @@
this.initShortcuts();
};
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.flagViewMessage = function ()
+ {
+ var oMessage = this.message();
+ if (oMessage)
+ {
+ require('App/User').messageListAction(oMessage.folderFullNameRaw, oMessage.uid,
+ oMessage.flagged() ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oMessage]);
+ }
+ };
+
/**
* @return {boolean}
*/
@@ -664,16 +813,26 @@
}
});
- key('ctrl+left, command+left, ctrl+up, command+up', Enums.KeyState.MessageView, function () {
+ key('ctrl+up, command+up', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
self.goUpCommand();
return false;
});
- key('ctrl+right, command+right, ctrl+down, command+down', Enums.KeyState.MessageView, function () {
+ key('ctrl+down, command+down', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
self.goDownCommand();
return false;
});
+ key('ctrl+left, command+left', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.threadForwardCommand();
+ return false;
+ });
+
+ key('ctrl+right, command+right', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.threadBackCommand();
+ return false;
+ });
+
// print
key('ctrl+p, command+p', Enums.KeyState.MessageView, function () {
if (self.message())
diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
index c5d83afb9..682b0439b 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php
@@ -49,7 +49,7 @@ class Config
/**
* @var int
*/
- public static $LargeThreadLimit = 100;
+ public static $LargeThreadLimit = 50;
/**
* @var bool
diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
index 262e69620..83dd2f66b 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
@@ -698,6 +698,18 @@ class MailClient
}
}
+ /**
+ * @return string
+ */
+ public function GenerateImapClientHash()
+ {
+ return \md5('ImapClientHash/'.
+ $this->oImapClient->GetLogginedUser().'@'.
+ $this->oImapClient->GetConnectedHost().':'.
+ $this->oImapClient->GetConnectedPort()
+ );
+ }
+
/**
* @param string $sFolder
* @param int $iCount
@@ -706,10 +718,12 @@ class MailClient
*
* @return string
*/
- public static function GenerateHash($sFolder, $iCount, $iUnseenCount, $sUidNext)
+ public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext)
{
$iUnseenCount = 0; // unneccessery
- return \md5($sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext);
+ return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'.
+ $this->GenerateImapClientHash()
+ );
}
/**
@@ -837,7 +851,7 @@ class MailClient
$aResult = array(
'Folder' => $sFolderName,
- 'Hash' => self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext),
+ 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext),
'MessageCount' => $iCount,
'MessageUnseenCount' => $iUnseenCount,
'UidNext' => $sUidNext,
@@ -866,7 +880,7 @@ class MailClient
$this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext);
- return self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext);
+ return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext);
}
/**
@@ -1410,7 +1424,8 @@ class MailClient
* @param string $sFolderHash
* @param array $aIndexOrUids
* @param \MailSo\Cache\CacheClient $oCacher
- * @param int $iThreadLimit = 100
+ * @param int $iThreadLimit = 50
+ * @param bool $bCacheOnly = false
*
* @return array
*
@@ -1418,7 +1433,7 @@ class MailClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
- public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $iThreadLimit = 100)
+ public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $iThreadLimit = 50, $bCacheOnly = false)
{
$iThreadLimit = \is_int($iThreadLimit) && 0 < $iThreadLimit ? $iThreadLimit : 0;
@@ -1438,30 +1453,36 @@ class MailClient
if ($oCacher && $oCacher->IsInited())
{
- $sSerializedHash =
+ $sSerializedHashKey =
'ThreadsMapSorted/'.$sSearchHash.'/'.
- 'Limit='.$iThreadLimit.'/'.
- $this->oImapClient->GetLogginedUser().'@'.
- $this->oImapClient->GetConnectedHost().':'.
- $this->oImapClient->GetConnectedPort().'/'.
- $sFolderName.'/'.$sFolderHash;
+ 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash;
- $sSerializedUids = $oCacher->Get($sSerializedHash);
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write($sSerializedHashKey);
+ }
+
+ $sSerializedUids = $oCacher->Get($sSerializedHashKey);
if (!empty($sSerializedUids))
{
- $aSerializedUids = @\unserialize($sSerializedUids);
- if (is_array($aSerializedUids))
+ $aSerializedUids = @\json_decode($sSerializedUids, true);
+ if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids']))
{
if ($this->oLogger)
{
- $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids).']');
+ $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']');
}
- return $aSerializedUids;
+ return $aSerializedUids['ThreadsUids'];
}
}
}
+ if ($bCacheOnly)
+ {
+ return null;
+ }
+
$this->oImapClient->FolderExamine($sFolderName);
$aThreadUids = array();
@@ -1471,6 +1492,7 @@ class MailClient
}
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
{
+ unset($oException);
$aThreadUids = array();
}
@@ -1582,9 +1604,11 @@ class MailClient
$aResult = $aLastResult;
unset($aLastResult);
- if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHash))
+ if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
{
- $oCacher->Set($sSerializedHash, serialize($aResult));
+ $oCacher->Set($sSerializedHashKey, @\json_encode(array(
+ 'ThreadsUids' => $aResult
+ )));
if ($this->oLogger)
{
@@ -1668,8 +1692,8 @@ class MailClient
private function getSearchUidsResult($sSearch, $sFolderName, $sFolderHash,
$bUseSortIfSupported = true, $bUseESearchOrESortRequest = false, $oCacher = null)
{
- $bUidsFromCacher = false;
$aResultUids = false;
+ $bUidsFromCacher = false;
$bUseCacheAfterSearch = true;
$sSerializedHash = '';
@@ -1680,23 +1704,21 @@ class MailClient
$sSearchCriterias = $this->getImapSearchCriterias($sSearch, 0, $bUseCacheAfterSearch);
if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
{
- $sSerializedHash =
+ $sSerializedHash = 'SearchSortUids/'.
($bUseSortIfSupported ? 'S': 'N').'/'.
- $this->oImapClient->GetLogginedUser().'@'.
- $this->oImapClient->GetConnectedHost().':'.
- $this->oImapClient->GetConnectedPort().'/'.
- $sFolderName.'/'.
- $sSearchCriterias;
+ $this->GenerateImapClientHash().'/'.
+ $sFolderName.'/'.$sSearchCriterias;
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
$sSerialized = $oCacher->Get($sSerializedHash);
if (!empty($sSerialized))
{
- $aSerialized = @\unserialize($sSerialized);
+ $aSerialized = @\json_decode($sSerialized, true);
if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
- \is_array($aSerialized['Uids']) &&
- ($sFolderHash === $aSerialized['FolderHash']))
+ $sFolderHash === $aSerialized['FolderHash'] &&
+ \is_array($aSerialized['Uids'])
+ )
{
if ($this->oLogger)
{
@@ -1779,7 +1801,7 @@ class MailClient
if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
{
- $oCacher->Set($sSerializedHash, \serialize(array(
+ $oCacher->Set($sSerializedHash, @\json_encode(array(
'FolderHash' => $sFolderHash,
'Uids' => $aResultUids
)));
@@ -1794,6 +1816,54 @@ class MailClient
return $aResultUids;
}
+ /**
+ * @param string $sFolderName
+ * @param string $sFolderHash
+ * @param string $sUid
+ * @param \MailSo\Cache\CacheClient|null $oCacher = null
+ *
+ * @return array
+ */
+ public function MessageThreadUidsFromCache($sFolderName, $sFolderHash, $sUid, $oCacher = null)
+ {
+ $aResult = array();
+ if (0 < \strlen($sFolderName) && 0 < \strlen($sFolderHash) && 0 < \strlen($sUid) && $oCacher && $oCacher->IsInited())
+ {
+ $mThreads = $this->MessageListThreadsMap($sFolderName, $sFolderHash, array(), $oCacher,
+ \MailSo\Config::$LargeThreadLimit, true);
+
+ if (\is_array($mThreads))
+ {
+ $iUid = (int) $sUid;
+ foreach ($mThreads as $iSubUid => $aSubUids)
+ {
+ if ($iUid === $iSubUid)
+ {
+ $aResult = $aSubUids;
+ if (!\is_array($aResult))
+ {
+ $aResult = array();
+ }
+
+ \array_unshift($aResult, $iSubUid);
+ break;
+ }
+ else if (\is_array($aSubUids))
+ {
+ if (\in_array($iUid, $aSubUids))
+ {
+ $aResult = $aSubUids;
+ \array_unshift($aResult, $iSubUid);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return \array_map('trim', $aResult);
+ }
+
/**
* @param string $sFolderName
* @param int $iOffset = 0
@@ -1803,7 +1873,6 @@ class MailClient
* @param \MailSo\Cache\CacheClient|null $oCacher = null
* @param bool $bUseSortIfSupported = false
* @param bool $bUseThreadSortIfSupported = false
- * @param array $aExpandedThreadsUids = array()
* @param bool $bUseESearchOrESortRequest = false
*
* @return \MailSo\Mail\MessageCollection
@@ -1812,9 +1881,8 @@ class MailClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
- public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '',
- $oCacher = null, $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false,
- $aExpandedThreadsUids = array(), $bUseESearchOrESortRequest = false)
+ public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null,
+ $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $bUseESearchOrESortRequest = false)
{
$sSearch = \trim($sSearch);
if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
@@ -1831,8 +1899,6 @@ class MailClient
$oMessageCollection->Limit = $iLimit;
$oMessageCollection->Search = $sSearch;
- $aLastCollapsedThreadUids = array();
-
$aThreads = array();
$iMessageCount = 0;
@@ -1853,7 +1919,7 @@ class MailClient
$this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
$iMessageCount = $iMessageRealCount;
- $oMessageCollection->FolderHash = self::GenerateHash($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
+ $oMessageCollection->FolderHash = $this->GenerateFolderHash($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
$oMessageCollection->UidNext = $sUidNext;
$oMessageCollection->NewMessages = $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext);
@@ -1889,11 +1955,9 @@ class MailClient
$oMessageCollection->FolderName, $oMessageCollection->FolderHash,
$bUseSortIfSupported, $bUseESearchOrESortRequest, $oCacher);
- $aThreads = $this->MessageListThreadsMap($oMessageCollection->FolderName, $oMessageCollection->FolderHash, $aIndexOrUids,
- $oCacher, \MailSo\Config::$LargeThreadLimit);
-
- $aExpandedThreadsUids = \is_array($aExpandedThreadsUids) ? $aExpandedThreadsUids : array();
- $bWatchExpanded = 0 < \count($aExpandedThreadsUids);
+ $aThreads = $this->MessageListThreadsMap(
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash,
+ $aIndexOrUids, $oCacher, \MailSo\Config::$LargeThreadLimit);
$aNewIndexOrUids = array();
foreach ($aIndexOrUids as $iUid)
@@ -1901,21 +1965,6 @@ class MailClient
if (isset($aThreads[$iUid]))
{
$aNewIndexOrUids[] = $iUid;
- if (\is_array($aThreads[$iUid]))
- {
- if ($bWatchExpanded && \in_array($iUid, $aExpandedThreadsUids))
- {
- $aSubArray = $aThreads[$iUid];
- foreach ($aSubArray as $iSubRootUid)
- {
- $aNewIndexOrUids[] = $iSubRootUid;
- }
- }
- else
- {
- $aLastCollapsedThreadUids[] = $iUid;
- }
- }
}
}
@@ -1966,38 +2015,20 @@ class MailClient
}
}
- $aLastCollapsedThreadUidsForPage = array();
-
if (!$bSearch && $bUseThreadSortIfSupported && 0 < \count($aThreads))
{
- $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use (
- $aThreads, $aLastCollapsedThreadUids, &$aLastCollapsedThreadUidsForPage)
- {
- $iUid = $oMessage->Uid();
- if (\in_array($iUid, $aLastCollapsedThreadUids))
- {
- $aLastCollapsedThreadUidsForPage[] = $iUid;
- }
+ $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($aThreads) {
+ $iUid = $oMessage->Uid();
if (isset($aThreads[$iUid]) && \is_array($aThreads[$iUid]) && 0 < \count($aThreads[$iUid]))
{
- $oMessage->SetThreads($aThreads[$iUid]);
- $oMessage->SetThreadsLen(\count($aThreads[$iUid]));
- }
- else if (!isset($aThreads[$iUid]))
- {
- foreach ($aThreads as $iKeyUid => $mSubItem)
- {
- if (\is_array($mSubItem) && \in_array($iUid, $mSubItem))
- {
- $oMessage->SetParentThread($iKeyUid);
- $oMessage->SetThreadsLen(\count($mSubItem));
- }
- }
+ $aSubThreads = $aThreads[$iUid];
+ \array_unshift($aSubThreads, $iUid);
+
+ $oMessage->SetThreads(\array_map('trim', $aSubThreads));
+ unset($aSubThreads);
}
});
-
- $oMessageCollection->LastCollapsedThreadUids = $aLastCollapsedThreadUidsForPage;
}
return $oMessageCollection;
diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php
index c2f9f71cd..7424f1bbf 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php
@@ -162,16 +162,6 @@ class Message
*/
private $aThreads;
- /**
- * @var int
- */
- private $iParentThread;
-
- /**
- * @var int
- */
- private $iThreadsLen;
-
/**
* @var bool
*/
@@ -240,8 +230,6 @@ class Message
$this->sReadReceipt = '';
$this->aThreads = array();
- $this->iThreadsLen = 0;
- $this->iParentThread = 0;
$this->bTextPartIsTrimmed = false;
@@ -542,38 +530,6 @@ class Message
$this->aThreads = \is_array($aThreads) ? $aThreads : array();
}
- /**
- * @return int
- */
- public function ThreadsLen()
- {
- return $this->iThreadsLen;
- }
-
- /**
- * @param int $iThreadsLen
- */
- public function SetThreadsLen($iThreadsLen)
- {
- $this->iThreadsLen = $iThreadsLen;
- }
-
- /**
- * @return int
- */
- public function ParentThread()
- {
- return $this->iParentThread;
- }
-
- /**
- * @param int $iParentThread
- */
- public function SetParentThread($iParentThread)
- {
- $this->iParentThread = $iParentThread;
- }
-
/**
* @return boole
*/
@@ -664,7 +620,8 @@ class Message
$this->oDeliveredTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::DELIVERED_TO, $bCharsetAutoDetect);
$this->sInReplyTo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::IN_REPLY_TO);
- $this->sReferences = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES);
+ $this->sReferences = \trim(\preg_replace('/[\s]+/', ' ',
+ $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES)));
$sHeaderDate = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::DATE);
$this->sHeaderDate = $sHeaderDate;
diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php
index 8d0c99b12..7bfaec046 100644
--- a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php
+++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php
@@ -256,7 +256,8 @@ class Message
*/
public function SetReferences($sReferences)
{
- $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] = $sReferences;
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] =
+ \trim(\preg_replace('/[\s]+/', ' ', $sReferences));
return $this;
}
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
index 9c702f064..19ce785b3 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php
@@ -5363,6 +5363,45 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, $aResult);
}
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessageThreadsFromCache()
+ {
+ $sFolder = $this->GetActionParam('Folder', '');
+ $sFolderHash = $this->GetActionParam('FolderHash', '');
+ $sUid = (string) $this->GetActionParam('Uid', '');
+
+ if (0 === \strlen($sFolder) || 0 === \strlen($sUid))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
+ }
+
+ $aResult = array(
+ 'Folder' => $sFolder,
+ 'Uid' => $sUid,
+ 'FolderHash' => $sFolderHash,
+ 'ThreadUids' => null
+ );
+
+ $oCache = $this->cacherForUids();
+ if ($oCache && $this->Config()->Get('labs', 'use_imap_thread', false))
+ {
+ $aThreadUids = $this->MailClient()->MessageThreadUidsFromCache(
+ $sFolder, $sFolderHash, $sUid, $oCache
+ );
+
+ if (\is_array($aThreadUids) && 1 < \count($aThreadUids))
+ {
+ $aResult['ThreadUids'] = $aThreadUids;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResult);
+ }
+
/**
* @return array
*
@@ -5379,7 +5418,6 @@ class Actions
$sSearch = '';
$sUidNext = '';
$bUseThreads = false;
- $sExpandedThreadUid = '';
$sRawKey = $this->GetActionParam('RawKey', '');
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
@@ -5392,7 +5430,6 @@ class Actions
$sSearch = (string) $aValues[3];
$sUidNext = (string) $aValues[6];
$bUseThreads = (bool) $aValues[7];
- $sExpandedThreadUid = (string) $aValues[8];
$this->verifyCacheByKey($sRawKey);
}
@@ -5404,7 +5441,6 @@ class Actions
$sSearch = $this->GetActionParam('Search', '');
$sUidNext = $this->GetActionParam('UidNext', '');
$bUseThreads = '1' === (string) $this->GetActionParam('UseThreads', '0');
- $sExpandedThreadUid = (string) $this->GetActionParam('ExpandedThreadUid', '');
}
if (0 === strlen($sFolder))
@@ -5419,29 +5455,13 @@ class Actions
if (!$this->Config()->Get('labs', 'use_imap_thread', false))
{
$bUseThreads = false;
- $sExpandedThreadUid = '';
- }
-
- $aExpandedThreadUid = array();
- if (0 < \strlen($sExpandedThreadUid))
- {
- $aExpandedThreadUid = \explode(',', $sExpandedThreadUid);
-
- $aExpandedThreadUid = \array_map(function ($sValue) {
- $sValue = \trim($sValue);
- return \is_numeric($sValue) ? (int) $sValue : 0;
- }, $aExpandedThreadUid);
-
- $aExpandedThreadUid = \array_filter($aExpandedThreadUid, function ($iValue) {
- return 0 < $iValue;
- });
}
$oMessageList = $this->MailClient()->MessageList(
$sFolder, $iOffset, $iLimit, $sSearch, $sUidNext,
$this->cacherForUids(),
!!$this->Config()->Get('labs', 'use_imap_sort', false),
- $bUseThreads, $aExpandedThreadUid,
+ $bUseThreads,
!!$this->Config()->Get('labs', 'use_imap_esearch_esort', false)
);
}
@@ -8875,8 +8895,6 @@ class Actions
'DeliveredTo' => $this->responseObject($mResponse->DeliveredTo(), $sParent, $aParameters),
'Priority' => $mResponse->Priority(),
'Threads' => $mResponse->Threads(),
- 'ThreadsLen' => $mResponse->ThreadsLen(),
- 'ParentThread' => $mResponse->ParentThread(),
'Sensitivity' => $mResponse->Sensitivity(),
'ExternalProxy' => false,
'ReadReceipt' => ''
@@ -9149,7 +9167,7 @@ class Actions
'MessageCount' => (int) $mStatus['MESSAGES'],
'MessageUnseenCount' => (int) $mStatus['UNSEEN'],
'UidNext' => (string) $mStatus['UIDNEXT'],
- 'Hash' => \MailSo\Mail\MailClient::GenerateHash(
+ 'Hash' => $this->MailClient()->GenerateFolderHash(
$mResponse->FullNameRaw(), $mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT'])
);
}
@@ -9179,7 +9197,7 @@ class Actions
'FolderHash' => $mResponse->FolderHash,
'UidNext' => $mResponse->UidNext,
'NewMessages' => $this->responseObject($mResponse->NewMessages),
- 'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
+// 'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
'Offset' => $mResponse->Offset,
'Limit' => $mResponse->Limit,
'Search' => $mResponse->Search
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
index ac183414e..c05c589fe 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php
@@ -92,7 +92,7 @@ class Api
(int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0);
\MailSo\Config::$LargeThreadLimit =
- (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 100);
+ (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50);
\MailSo\Config::$SystemLogger = \RainLoop\Api::Logger();
diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
index d8eccb6d9..0ef1d88cd 100644
--- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
+++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php
@@ -291,7 +291,7 @@ Enables caching in the system'),
'imap_message_list_fast_simple_search' => array(true),
'imap_message_list_count_limit_trigger' => array(0),
'imap_message_list_date_filter' => array(0),
- 'imap_large_thread_limit' => array(100),
+ 'imap_large_thread_limit' => array(50),
'imap_folder_list_limit' => array(200),
'imap_show_login_alert' => array(true),
'smtp_show_server_errors' => array(false),
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
index 24d8a6c2e..6aec37979 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItem.html
@@ -22,13 +22,12 @@
-
-
- x
-
+
+ ()
+
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html
index 9bb8dc536..960345fa0 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageListItemNoPreviewPane.html
@@ -22,13 +22,12 @@
-
-
- x
-
+
+ ()
+
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html
index a7ce09233..c691b7491 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/MailMessageView.html
@@ -182,14 +182,14 @@
-