mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-09-14 00:54:18 +08:00
New thread list logic (step 2)
This commit is contained in:
parent
b656b6365b
commit
03d26bc4c6
18 changed files with 139 additions and 517 deletions
|
@ -153,20 +153,7 @@
|
||||||
Cache.initMessageFlagsFromCache(oMessage);
|
Cache.initMessageFlagsFromCache(oMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(MessageStore.messageThreadList(), function (oMessage) {
|
|
||||||
Cache.initMessageFlagsFromCache(oMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
Cache.initMessageFlagsFromCache(MessageStore.message());
|
Cache.initMessageFlagsFromCache(MessageStore.message());
|
||||||
|
|
||||||
this.reloadFlagsCurrentMessageThreadListFromCache();
|
|
||||||
};
|
|
||||||
|
|
||||||
AppUser.prototype.reloadFlagsCurrentMessageThreadListFromCache = function ()
|
|
||||||
{
|
|
||||||
_.each(MessageStore.messageThreadList(), function (oMessage) {
|
|
||||||
Cache.initMessageFlagsFromCache(oMessage);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -272,7 +272,7 @@
|
||||||
|
|
||||||
if ('' !== sFolder)
|
if ('' !== sFolder)
|
||||||
{
|
{
|
||||||
sResult += encodeURI(sFolder) + (0 < iThreadUid ? '|' + iThreadUid : '');
|
sResult += encodeURI(sFolder) + (0 < iThreadUid ? '~' + iThreadUid : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1 < iPage)
|
if (1 < iPage)
|
||||||
|
|
|
@ -633,13 +633,20 @@
|
||||||
|
|
||||||
var
|
var
|
||||||
iOffset = 20,
|
iOffset = 20,
|
||||||
|
aList = this.list(),
|
||||||
oFocused = $(this.sItemFocusedSelector, this.oContentScrollable),
|
oFocused = $(this.sItemFocusedSelector, this.oContentScrollable),
|
||||||
oPos = oFocused.position(),
|
oPos = oFocused.position(),
|
||||||
iVisibleHeight = this.oContentVisible.height(),
|
iVisibleHeight = this.oContentVisible.height(),
|
||||||
iFocusedHeight = oFocused.outerHeight()
|
iFocusedHeight = oFocused.outerHeight()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight))
|
if (aList && aList[0] && aList[0].focused())
|
||||||
|
{
|
||||||
|
this.oContentScrollable.scrollTop(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight))
|
||||||
{
|
{
|
||||||
if (oPos.top < 0)
|
if (oPos.top < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,44 +29,10 @@
|
||||||
function UserAjaxUserPromises()
|
function UserAjaxUserPromises()
|
||||||
{
|
{
|
||||||
AbstractAjaxPromises.call(this);
|
AbstractAjaxPromises.call(this);
|
||||||
|
|
||||||
this.messageListSimpleHash = '';
|
|
||||||
this.messageListSimpleCache = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype);
|
_.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype);
|
||||||
|
|
||||||
UserAjaxUserPromises.prototype.messageListSimple = function (sFolder, aUids, fTrigger)
|
|
||||||
{
|
|
||||||
var self = this, sHash = sFolder + '~' + aUids.join('/');
|
|
||||||
if (sHash === this.messageListSimpleHash && this.messageListSimpleCache)
|
|
||||||
{
|
|
||||||
return this.fastResolve(this.messageListSimpleCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.abort('MessageListSimple')
|
|
||||||
.postRequest('MessageListSimple', fTrigger, {
|
|
||||||
'Folder': sFolder,
|
|
||||||
'Uids': aUids
|
|
||||||
}).then(function (oData) {
|
|
||||||
|
|
||||||
self.messageListSimpleHash = sHash;
|
|
||||||
self.messageListSimpleCache = _.compact(_.map(oData.Result, function (aItem) {
|
|
||||||
return MessageSimpleModel.newInstanceFromJson(aItem);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return self.messageListSimpleCache;
|
|
||||||
|
|
||||||
}, function (iError) {
|
|
||||||
|
|
||||||
self.messageListSimpleHash = '';
|
|
||||||
self.messageListSimpleCache = null;
|
|
||||||
|
|
||||||
return self.fastReject(iError);
|
|
||||||
})
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
UserAjaxUserPromises.prototype.foldersReload = function (fTrigger)
|
UserAjaxUserPromises.prototype.foldersReload = function (fTrigger)
|
||||||
{
|
{
|
||||||
return this.abort('Folders')
|
return this.abort('Folders')
|
||||||
|
|
|
@ -313,19 +313,6 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?Function} fCallback
|
|
||||||
* @param {string} sFolderFullNameRaw
|
|
||||||
* @param {Array} aUids
|
|
||||||
*/
|
|
||||||
RemoteUserAjax.prototype.messageListSimple = function (fCallback, sFolderFullNameRaw, aUids)
|
|
||||||
{
|
|
||||||
return this.defaultRequest(fCallback, 'MessageListSimple', {
|
|
||||||
'Folder': Utils.pString(sFolderFullNameRaw),
|
|
||||||
'Uids': aUids
|
|
||||||
}, Consts.Defaults.DefaultAjaxTimeout, '', ['MessageListSimple']);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {?Function} fCallback
|
* @param {?Function} fCallback
|
||||||
* @param {string} sFolderFullNameRaw
|
* @param {string} sFolderFullNameRaw
|
||||||
|
@ -420,35 +407,6 @@
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?Function} fCallback
|
|
||||||
* @param {string} sFolderFullNameRaw
|
|
||||||
* @param {number} iUid
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
RemoteUserAjax.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 {?Function} fCallback
|
||||||
* @param {Array} aExternals
|
* @param {Array} aExternals
|
||||||
|
|
|
@ -75,9 +75,9 @@
|
||||||
MailBoxUserScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch)
|
MailBoxUserScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch)
|
||||||
{
|
{
|
||||||
var
|
var
|
||||||
sThreadUid = sFolderHash.replace(/^(.+)\|([\d]+)$/, '$2'),
|
sThreadUid = sFolderHash.replace(/^(.+)~([\d]+)$/, '$2'),
|
||||||
oFolder = Cache.getFolderFromCacheList(Cache.getFolderFullNameRaw(
|
oFolder = Cache.getFolderFromCacheList(Cache.getFolderFullNameRaw(
|
||||||
sFolderHash.replace(/\|([\d]+)$/, '')))
|
sFolderHash.replace(/~([\d]+)$/, '')))
|
||||||
;
|
;
|
||||||
|
|
||||||
if (oFolder)
|
if (oFolder)
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderStore.currentFolder(oFolder);
|
FolderStore.currentFolder(oFolder);
|
||||||
|
|
||||||
MessageStore.messageListPage(iPage);
|
MessageStore.messageListPage(iPage);
|
||||||
MessageStore.messageListSearch(sSearch);
|
MessageStore.messageListSearch(sSearch);
|
||||||
MessageStore.messageListThreadUid(sThreadUid);
|
MessageStore.messageListThreadUid(sThreadUid);
|
||||||
|
@ -171,9 +171,9 @@
|
||||||
;
|
;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
[/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)\/(.+)\/?$/, {'normalize_': fNormS}],
|
[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)\/(.+)\/?$/, {'normalize_': fNormS}],
|
||||||
[/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)$/, {'normalize_': fNormS}],
|
[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)$/, {'normalize_': fNormS}],
|
||||||
[/^([a-zA-Z0-9]+)\/(.+)\/?$/, {'normalize_': fNormD}],
|
[/^([a-zA-Z0-9~]+)\/(.+)\/?$/, {'normalize_': fNormD}],
|
||||||
[/^([^\/]*)$/, {'normalize_': fNormS}]
|
[/^([^\/]*)$/, {'normalize_': fNormS}]
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,10 +43,12 @@
|
||||||
this.messageListSearch = ko.observable('');
|
this.messageListSearch = ko.observable('');
|
||||||
this.messageListThreadUid = ko.observable('');
|
this.messageListThreadUid = ko.observable('');
|
||||||
this.messageListPage = ko.observable(1);
|
this.messageListPage = ko.observable(1);
|
||||||
|
this.messageListPageBeforeThread = ko.observable(1);
|
||||||
this.messageListError = ko.observable('');
|
this.messageListError = ko.observable('');
|
||||||
|
|
||||||
this.messageListEndFolder = ko.observable('');
|
this.messageListEndFolder = ko.observable('');
|
||||||
this.messageListEndSearch = ko.observable('');
|
this.messageListEndSearch = ko.observable('');
|
||||||
|
this.messageListEndThreadUid = ko.observable('');
|
||||||
this.messageListEndPage = ko.observable(1);
|
this.messageListEndPage = ko.observable(1);
|
||||||
|
|
||||||
this.messageListLoading = ko.observable(false);
|
this.messageListLoading = ko.observable(false);
|
||||||
|
@ -64,17 +66,12 @@
|
||||||
|
|
||||||
this.message.viewTrigger = ko.observable(false);
|
this.message.viewTrigger = ko.observable(false);
|
||||||
|
|
||||||
this.messageThreadList = ko.observableArray([]);
|
|
||||||
|
|
||||||
this.messageLastThreadUidsData = ko.observable(null);
|
|
||||||
|
|
||||||
this.messageError = ko.observable('');
|
this.messageError = ko.observable('');
|
||||||
|
|
||||||
this.messageCurrentLoading = ko.observable(false);
|
this.messageCurrentLoading = ko.observable(false);
|
||||||
this.messageThreadLoading = ko.observable(false);
|
|
||||||
|
|
||||||
this.messageLoading = ko.computed(function () {
|
this.messageLoading = ko.computed(function () {
|
||||||
return !!(this.messageCurrentLoading() || this.messageThreadLoading());
|
return this.messageCurrentLoading();
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
|
this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
|
||||||
|
@ -94,8 +91,12 @@
|
||||||
|
|
||||||
MessageUserStore.prototype.computers = function ()
|
MessageUserStore.prototype.computers = function ()
|
||||||
{
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
this.messageListEndHash = ko.computed(function () {
|
this.messageListEndHash = ko.computed(function () {
|
||||||
return this.messageListEndFolder() + '|' + this.messageListEndSearch() + '|' + this.messageListEndPage();
|
return this.messageListEndFolder() + '|' + this.messageListEndSearch() +
|
||||||
|
'|' + this.messageListEndThreadUid() +
|
||||||
|
'|' + this.messageListEndPage();
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.messageListPageCount = ko.computed(function () {
|
this.messageListPageCount = ko.computed(function () {
|
||||||
|
@ -108,7 +109,8 @@
|
||||||
'read': this.messageListSearch,
|
'read': this.messageListSearch,
|
||||||
'write': function (sValue) {
|
'write': function (sValue) {
|
||||||
kn.setHash(Links.mailBox(
|
kn.setHash(Links.mailBox(
|
||||||
FolderStore.currentFolderFullNameHash(), 1, Utils.trim(sValue.toString())
|
FolderStore.currentFolderFullNameHash(), 1,
|
||||||
|
Utils.trim(sValue.toString()), self.messageListThreadUid()
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
'owner': this
|
'owner': this
|
||||||
|
@ -666,14 +668,6 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MessageUserStore.prototype.selectThreadMessage = function (sFolder, sUid)
|
|
||||||
{
|
|
||||||
if (Remote.message(this.onMessageResponse, sFolder, sUid))
|
|
||||||
{
|
|
||||||
this.messageThreadLoading(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MessageUserStore.prototype.populateMessageBody = function (oMessage)
|
MessageUserStore.prototype.populateMessageBody = function (oMessage)
|
||||||
{
|
{
|
||||||
if (oMessage)
|
if (oMessage)
|
||||||
|
@ -695,7 +689,6 @@
|
||||||
this.hideMessageBodies();
|
this.hideMessageBodies();
|
||||||
|
|
||||||
this.messageCurrentLoading(false);
|
this.messageCurrentLoading(false);
|
||||||
this.messageThreadLoading(false);
|
|
||||||
|
|
||||||
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
{
|
{
|
||||||
|
@ -817,7 +810,8 @@
|
||||||
this.messageListThreadUid(Utils.isNormal(oData.Result.ThreadUid) ? Utils.pString(oData.Result.ThreadUid) : '');
|
this.messageListThreadUid(Utils.isNormal(oData.Result.ThreadUid) ? Utils.pString(oData.Result.ThreadUid) : '');
|
||||||
|
|
||||||
this.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
|
this.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
|
||||||
this.messageListEndSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
|
this.messageListEndSearch(this.messageListSearch());
|
||||||
|
this.messageListEndThreadUid(this.messageListThreadUid());
|
||||||
this.messageListEndPage(this.messageListPage());
|
this.messageListEndPage(this.messageListPage());
|
||||||
|
|
||||||
this.messageListDisableAutoSelect(true);
|
this.messageListDisableAutoSelect(true);
|
||||||
|
@ -827,26 +821,6 @@
|
||||||
|
|
||||||
Cache.clearNewMessageCache();
|
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()))
|
if (oFolder && (bCached || bUnreadCountChange || SettingsStore.useThreads()))
|
||||||
{
|
{
|
||||||
require('App/User').folderInformation(oFolder.fullNameRaw, aList);
|
require('App/User').folderInformation(oFolder.fullNameRaw, aList);
|
||||||
|
|
|
@ -178,6 +178,15 @@ html.rl-no-preview-pane {
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.listThreadUidDesc {
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 7px 20px 5px 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
background-color: #FCF8E3;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.delimiter {
|
.delimiter {
|
||||||
display: block;
|
display: block;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
|
@ -313,6 +322,12 @@ html.rl-no-preview-pane {
|
||||||
&.e-single-line .dateParent {
|
&.e-single-line .dateParent {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.threadsParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.attachmentParent {
|
.attachmentParent {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -398,8 +413,13 @@ html.rl-no-preview-pane {
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 1px 6px 1px 5px;
|
padding: 1px 2px 1px 5px;
|
||||||
margin-right: 5px;
|
margin-right: 2px;
|
||||||
|
|
||||||
|
[class^="icon-"],
|
||||||
|
[class*=" icon-"] {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-top-color: #999;
|
border-top-color: #999;
|
||||||
|
|
||||||
animation: rotation .8s infinite linear;
|
animation: rotation .8s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.big {
|
&.big {
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
|
|
||||||
this.mainMessageListSearch = MessageStore.mainMessageListSearch;
|
this.mainMessageListSearch = MessageStore.mainMessageListSearch;
|
||||||
this.messageListEndFolder = MessageStore.messageListEndFolder;
|
this.messageListEndFolder = MessageStore.messageListEndFolder;
|
||||||
|
this.messageListEndThreadUid = MessageStore.messageListEndThreadUid;
|
||||||
|
|
||||||
this.messageListChecked = MessageStore.messageListChecked;
|
this.messageListChecked = MessageStore.messageListChecked;
|
||||||
this.messageListCheckedOrSelected = MessageStore.messageListCheckedOrSelected;
|
this.messageListCheckedOrSelected = MessageStore.messageListCheckedOrSelected;
|
||||||
|
@ -389,6 +390,15 @@
|
||||||
this.inputMessageListSearchFocus(false);
|
this.inputMessageListSearchFocus(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MessageListMailBoxUserView.prototype.cancelThreadUid = function ()
|
||||||
|
{
|
||||||
|
kn.setHash(Links.mailBox(
|
||||||
|
FolderStore.currentFolderFullNameHash(),
|
||||||
|
MessageStore.messageListPageBeforeThread(),
|
||||||
|
MessageStore.messageListSearch()
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} sToFolderFullNameRaw
|
* @param {string} sToFolderFullNameRaw
|
||||||
* @param {boolean} bCopy
|
* @param {boolean} bCopy
|
||||||
|
@ -618,6 +628,21 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MessageListMailBoxUserView.prototype.gotoThread = function (oMessage)
|
||||||
|
{
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
MessageStore.messageListPageBeforeThread(MessageStore.messageListPage());
|
||||||
|
|
||||||
|
kn.setHash(Links.mailBox(
|
||||||
|
FolderStore.currentFolderFullNameHash(),
|
||||||
|
1,
|
||||||
|
MessageStore.messageListSearch(),
|
||||||
|
oMessage.uid
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
MessageListMailBoxUserView.prototype.onBuild = function (oDom)
|
MessageListMailBoxUserView.prototype.onBuild = function (oDom)
|
||||||
{
|
{
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -643,6 +668,9 @@
|
||||||
.on('click', '.messageList .messageListItem .flagParent', function () {
|
.on('click', '.messageList .messageListItem .flagParent', function () {
|
||||||
self.flagMessages(ko.dataFor(this));
|
self.flagMessages(ko.dataFor(this));
|
||||||
})
|
})
|
||||||
|
.on('click', '.messageList .messageListItem .threads-len', function () {
|
||||||
|
self.gotoThread(ko.dataFor(this));
|
||||||
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
this.initUploaderForAppend();
|
this.initUploaderForAppend();
|
||||||
|
@ -725,6 +753,22 @@
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
key('t', [Enums.KeyState.MessageList], function () {
|
||||||
|
|
||||||
|
var oMessage = self.selectorMessageSelected();
|
||||||
|
if (!oMessage)
|
||||||
|
{
|
||||||
|
oMessage = self.selectorMessageFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oMessage && 0 < oMessage.threadsLen())
|
||||||
|
{
|
||||||
|
self.gotoThread(oMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// move
|
// move
|
||||||
key('m', Enums.KeyState.MessageList, function () {
|
key('m', Enums.KeyState.MessageList, function () {
|
||||||
self.moveDropdownTrigger(true);
|
self.moveDropdownTrigger(true);
|
||||||
|
@ -761,6 +805,11 @@
|
||||||
self.cancelSearch();
|
self.cancelSearch();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if ('' !== self.messageListEndThreadUid())
|
||||||
|
{
|
||||||
|
self.cancelThreadUid();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// change focused state
|
// change focused state
|
||||||
|
|
|
@ -229,164 +229,6 @@
|
||||||
this.viewIsImportant = ko.observable(false);
|
this.viewIsImportant = ko.observable(false);
|
||||||
this.viewIsFlagged = ko.observable(false);
|
this.viewIsFlagged = ko.observable(false);
|
||||||
|
|
||||||
// THREADS
|
|
||||||
this.viewThreads = ko.observableArray([]);
|
|
||||||
this.viewThreads.trigger = ko.observable(false);
|
|
||||||
|
|
||||||
this.viewThreadMessages = MessageStore.messageThreadList;
|
|
||||||
|
|
||||||
this.viewThreadMessages.error = ko.observable('');
|
|
||||||
this.viewThreadMessages.showMore = ko.observable(false);
|
|
||||||
this.viewThreadMessages.limit = 6;
|
|
||||||
|
|
||||||
this.viewThreadMessages.subscribe(function (aList) {
|
|
||||||
|
|
||||||
var iSelectedIndex = -1;
|
|
||||||
|
|
||||||
this.viewThreadMessages.error('');
|
|
||||||
if (aList && 0 < aList.length)
|
|
||||||
{
|
|
||||||
_.each(aList, function (oM, iIndex) {
|
|
||||||
if (oM && oM.selected())
|
|
||||||
{
|
|
||||||
iSelectedIndex = iIndex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.viewThreadMessages.showMore(this.viewThreadMessages.limit >= aList.length);
|
|
||||||
|
|
||||||
if (-1 < iSelectedIndex && !this.viewThreadMessages.showMore() &&
|
|
||||||
this.viewThreadMessages.limit < iSelectedIndex)
|
|
||||||
{
|
|
||||||
this.viewThreadMessages.showMore(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectSelectedThreadMessage();
|
|
||||||
require('App/User').reloadFlagsCurrentMessageListAndMessageFromCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
this.threadsDropdownTrigger = ko.observable(false);
|
|
||||||
|
|
||||||
this.threadListCommand = Utils.createCommand(this, function () {
|
|
||||||
|
|
||||||
var
|
|
||||||
self = this,
|
|
||||||
sFolder = this.viewFolder,
|
|
||||||
sUid = this.viewUid,
|
|
||||||
aUids = this.viewThreads(),
|
|
||||||
aStatus = this.viewThreads.status()
|
|
||||||
;
|
|
||||||
|
|
||||||
if (aStatus && aStatus[0])
|
|
||||||
{
|
|
||||||
self.viewThreadMessages([]);
|
|
||||||
|
|
||||||
Promises.messageListSimple(sFolder, aUids, this.messageListOfThreadsLoading).then(function (aList) {
|
|
||||||
|
|
||||||
_.each(aList, function (oItem) {
|
|
||||||
if (oItem && oItem.uid)
|
|
||||||
{
|
|
||||||
oItem.selected(sUid === oItem.uid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.viewThreadMessages(aList);
|
|
||||||
|
|
||||||
}).fail(function (iErrorCode) {
|
|
||||||
self.viewThreadMessages([]);
|
|
||||||
self.viewThreadMessages.error(Translator.getNotification(
|
|
||||||
iErrorCode, '', Enums.Notification.CantGetMessageList));
|
|
||||||
}).done();
|
|
||||||
}
|
|
||||||
|
|
||||||
}, function () {
|
|
||||||
return !this.messageLoadingThrottle() &&
|
|
||||||
!this.messageListOfThreadsLoading();
|
|
||||||
});
|
|
||||||
|
|
||||||
// PGP
|
// PGP
|
||||||
this.viewPgpPassword = ko.observable('');
|
this.viewPgpPassword = ko.observable('');
|
||||||
this.viewPgpSignedVerifyStatus = ko.computed(function () {
|
this.viewPgpSignedVerifyStatus = ko.computed(function () {
|
||||||
|
@ -472,9 +314,6 @@
|
||||||
this.viewIsImportant(oMessage.isImportant());
|
this.viewIsImportant(oMessage.isImportant());
|
||||||
this.viewIsFlagged(oMessage.flagged());
|
this.viewIsFlagged(oMessage.flagged());
|
||||||
|
|
||||||
this.viewThreads(oMessage.threads());
|
|
||||||
this.viewThreads.trigger(!this.viewThreads.trigger());
|
|
||||||
|
|
||||||
sLastEmail = oMessage.fromAsSingleEmail();
|
sLastEmail = oMessage.fromAsSingleEmail();
|
||||||
Cache.getUserPic(sLastEmail, function (sPic, sEmail) {
|
Cache.getUserPic(sLastEmail, function (sPic, sEmail) {
|
||||||
if (sPic !== self.viewUserPic() && sLastEmail === sEmail)
|
if (sPic !== self.viewUserPic() && sLastEmail === sEmail)
|
||||||
|
@ -495,8 +334,6 @@
|
||||||
this.viewUid = '';
|
this.viewUid = '';
|
||||||
this.viewHash = '';
|
this.viewHash = '';
|
||||||
|
|
||||||
this.viewThreads([]);
|
|
||||||
|
|
||||||
this.scrollMessageToTop();
|
this.scrollMessageToTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,15 +392,6 @@
|
||||||
kn.extendAsViewModel(['View/User/MailBox/MessageView', 'View/App/MailBox/MessageView', 'MailBoxMessageViewViewModel'], MessageViewMailBoxUserView);
|
kn.extendAsViewModel(['View/User/MailBox/MessageView', 'View/App/MailBox/MessageView', 'MailBoxMessageViewViewModel'], MessageViewMailBoxUserView);
|
||||||
_.extend(MessageViewMailBoxUserView.prototype, AbstractView.prototype);
|
_.extend(MessageViewMailBoxUserView.prototype, AbstractView.prototype);
|
||||||
|
|
||||||
MessageViewMailBoxUserView.prototype.openThreadMessage = function (sUid)
|
|
||||||
{
|
|
||||||
var oMessage = this.message();
|
|
||||||
if (oMessage && sUid)
|
|
||||||
{
|
|
||||||
MessageStore.selectThreadMessage(oMessage.folderFullNameRaw, sUid);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MessageViewMailBoxUserView.prototype.isPgpActionVisible = function ()
|
MessageViewMailBoxUserView.prototype.isPgpActionVisible = function ()
|
||||||
{
|
{
|
||||||
return Enums.SignedVerifyStatus.Success !== this.viewPgpSignedVerifyStatus();
|
return Enums.SignedVerifyStatus.Success !== this.viewPgpSignedVerifyStatus();
|
||||||
|
@ -791,32 +619,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('click', '.thread-list .more-threads', function (e) {
|
|
||||||
|
|
||||||
var oLast = null;
|
|
||||||
if (!e || 0 === e.clientX) // probably enter
|
|
||||||
{
|
|
||||||
// It's a bad bad hack :(
|
|
||||||
oLast = $('.thread-list .e-item.thread-list-message.real-msg.more-that:first a.e-link', oDom);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.viewThreadMessages.showMore(true);
|
|
||||||
self.threadsDropdownTrigger(true);
|
|
||||||
|
|
||||||
if (oLast && oLast[0])
|
|
||||||
{
|
|
||||||
oLast.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
.on('click', '.thread-list .thread-list-message', function () {
|
|
||||||
var oMessage = ko.dataFor(this);
|
|
||||||
if (oMessage && oMessage.folder && oMessage.uid)
|
|
||||||
{
|
|
||||||
self.openThreadMessage(oMessage.uid);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () {
|
.on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () {
|
||||||
|
|
||||||
var
|
var
|
||||||
|
@ -970,35 +772,16 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
key('t', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
|
key('ctrl+up, command+up, ctrl+left, command+left', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
|
||||||
if (MessageStore.message() && self.viewThreadsControlVisibility())
|
|
||||||
{
|
|
||||||
self.threadsDropdownTrigger(true);
|
|
||||||
self.threadListCommand();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
key('ctrl+up, command+up', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
|
|
||||||
self.goUpCommand();
|
self.goUpCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
key('ctrl+down, command+down', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
|
key('ctrl+down, command+down, ctrl+right, command+right', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
|
||||||
self.goDownCommand();
|
self.goDownCommand();
|
||||||
return false;
|
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
|
// print
|
||||||
key('ctrl+p, command+p', Enums.KeyState.MessageView, function () {
|
key('ctrl+p, command+p', Enums.KeyState.MessageView, function () {
|
||||||
if (self.message())
|
if (self.message())
|
||||||
|
|
|
@ -1916,6 +1916,7 @@ class MailClient
|
||||||
* @param string $sSearch
|
* @param string $sSearch
|
||||||
* @param string $sFolderName
|
* @param string $sFolderName
|
||||||
* @param string $sFolderHash
|
* @param string $sFolderHash
|
||||||
|
* @param bool $bUseSortIfSupported = false
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
|
@ -1923,7 +1924,7 @@ class MailClient
|
||||||
* @throws \MailSo\Net\Exceptions\Exception
|
* @throws \MailSo\Net\Exceptions\Exception
|
||||||
* @throws \MailSo\Imap\Exceptions\Exception
|
* @throws \MailSo\Imap\Exceptions\Exception
|
||||||
*/
|
*/
|
||||||
public function GetUids($oCacher, $sSearch, $sFolderName, $sFolderHash)
|
public function GetUids($oCacher, $sSearch, $sFolderName, $sFolderHash, $bUseSortIfSupported = false)
|
||||||
{
|
{
|
||||||
$aResultUids = false;
|
$aResultUids = false;
|
||||||
$bUidsFromCacher = false;
|
$bUidsFromCacher = false;
|
||||||
|
@ -1932,7 +1933,7 @@ class MailClient
|
||||||
$sSerializedHash = '';
|
$sSerializedHash = '';
|
||||||
$sSerializedLog = '';
|
$sSerializedLog = '';
|
||||||
|
|
||||||
$bUseSortIfSupported = !!$this->oImapClient->IsSupported('SORT');
|
$bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false;
|
||||||
|
|
||||||
if (0 < \strlen($sSearch))
|
if (0 < \strlen($sSearch))
|
||||||
{
|
{
|
||||||
|
@ -2078,7 +2079,11 @@ class MailClient
|
||||||
|
|
||||||
if (0 < $iMessageRealCount)
|
if (0 < $iMessageRealCount)
|
||||||
{
|
{
|
||||||
$mAllSortedUids = $this->GetUids($oCacher, '', $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
|
$mAllSortedUids = $this->GetUids($oCacher, '', $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported);
|
||||||
|
|
||||||
|
$bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false;
|
||||||
|
|
||||||
|
// $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ?
|
||||||
|
|
||||||
$mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
|
$mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
|
||||||
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
|
$oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
|
||||||
|
|
|
@ -5455,45 +5455,6 @@ class Actions
|
||||||
return $this->DefaultResponse(__FUNCTION__, $aResult);
|
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
|
* @return array
|
||||||
*
|
*
|
||||||
|
@ -5501,7 +5462,7 @@ class Actions
|
||||||
*/
|
*/
|
||||||
public function DoMessageList()
|
public function DoMessageList()
|
||||||
{
|
{
|
||||||
// \sleep(1);
|
\sleep(1);
|
||||||
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
|
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
|
||||||
|
|
||||||
$sFolder = '';
|
$sFolder = '';
|
||||||
|
@ -5581,40 +5542,6 @@ class Actions
|
||||||
return $this->DefaultResponse(__FUNCTION__, $oMessageList);
|
return $this->DefaultResponse(__FUNCTION__, $oMessageList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @throws \MailSo\Base\Exceptions\Exception
|
|
||||||
*/
|
|
||||||
public function DoMessageListSimple()
|
|
||||||
{
|
|
||||||
// \sleep(2);
|
|
||||||
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
|
|
||||||
|
|
||||||
$sFolder = $this->GetActionParam('Folder', '');
|
|
||||||
$aUids = $this->GetActionParam('Uids', null);
|
|
||||||
|
|
||||||
if (0 === \strlen($sFolder) || !\is_array($aUids))
|
|
||||||
{
|
|
||||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->initMailClientConnection();
|
|
||||||
|
|
||||||
$aMessageList = array();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$aMessageList = $this->MailClient()->MessageListSimple($sFolder, $aUids);
|
|
||||||
}
|
|
||||||
catch (\Exception $oException)
|
|
||||||
{
|
|
||||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $aMessageList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \RainLoop\Model\Account $oAccount
|
* @param \RainLoop\Model\Account $oAccount
|
||||||
* @param bool $bWithDraftInfo = true
|
* @param bool $bWithDraftInfo = true
|
||||||
|
|
|
@ -42,12 +42,12 @@
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_CHECK_ALL"></td><td>Ctrl + A, Cmd + A</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_CHECK_ALL"></td><td>Ctrl + A, Cmd + A</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_ARCHIVE"></td><td>Z</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_ARCHIVE"></td><td>Z</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_DELETE"></td><td>Delete, Shift + Delete, #</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_DELETE"></td><td>Delete, Shift + Delete, #</td></tr>
|
||||||
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_OPEN_THREAD"></td><td>T</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_MOVE"></td><td>M</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_MOVE"></td><td>M</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_READ"></td><td>Q</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_READ"></td><td>Q</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_UNREAD"></td><td>U</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_UNREAD"></td><td>U</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_IMPORTANT"></td><td>I</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_IMPORTANT"></td><td>I</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SEARCH"></td><td>/</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SEARCH"></td><td>/</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_CANCEL_SEARCH"></td><td>Esc</td></tr>
|
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_ENTER"></td><td>Enter</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_ENTER"></td><td>Enter</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_VIEW_MESSAGE_ENTER"></td><td>Enter</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_VIEW_MESSAGE_ENTER"></td><td>Enter</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_MESSAGE"></td><td>→, Tab</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_MESSAGE"></td><td>→, Tab</td></tr>
|
||||||
|
@ -60,14 +60,12 @@
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_TOGGLE">Toggle fullscreen mode</td><td>Enter</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_FULLSCREEN_TOGGLE"></td><td>Enter</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_BLOCKQUOTES_TOGGLE">Toggle message blockquotes</td><td>B</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_BLOCKQUOTES_TOGGLE"></td><td>B</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_THREAD_NEXT">Next message in thread</td><td>Ctrl + ←, Cmd + ←</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_PRINT"></td><td>Ctrl + P, Cmd + P</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_THREAD_PREV">Previous message in thread</td><td>Ctrl + →, Cmd + →</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_EXIT_FULLSCREEN"></td><td>Esc</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_PRINT">Print</td><td>Ctrl + P, Cmd + P</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_MESSAGE"></td><td>Esc</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_EXIT_FULLSCREEN">Exit fullscreen mode</td><td>Esc</td></tr>
|
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_LIST"></td><td>Tab, Shift + Tab, Esc</td></tr>
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_CLOSE_MESSAGE">Close message (No preview pane layout)</td><td>Esc</td></tr>
|
|
||||||
<tr><td class="i18n" data-i18n="SHORTCUTS_HELP/LABEL_SWITCH_TO_LIST">Switch focus back to message list</td><td>Tab, Shift + Tab, Esc</td></tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -137,12 +137,14 @@
|
||||||
<div class="b-content" data-bind="nano: true, initDom: dragOverBodyArea">
|
<div class="b-content" data-bind="nano: true, initDom: dragOverBodyArea">
|
||||||
<div class="content g-scrollbox">
|
<div class="content g-scrollbox">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
<div class="listThreadUidDesc" data-bind="visible: '' !== messageListEndThreadUid(), click: cancelThreadUid">
|
||||||
|
<i class="icon-left" data-bind="click: cancelThreadUid"></i>
|
||||||
|
|
||||||
|
<span class="i18n" data-i18n="MESSAGE_LIST/BACK_TO_MESSAGE_LIST"></span>
|
||||||
|
</div>
|
||||||
<div class="listSearchDesc" data-bind="visible: '' !== messageListSearchDesc()">
|
<div class="listSearchDesc" data-bind="visible: '' !== messageListSearchDesc()">
|
||||||
<a class="close-custom" data-bind="click: cancelSearch">×</a>
|
<a class="close-custom" data-bind="click: cancelSearch">×</a>
|
||||||
<!-- <a class="btn btn-small pull-right searchCancelButton" data-bind="click: cancelSearch">
|
<span data-bind="text: messageListSearchDesc"></span>
|
||||||
<i class="icon-remove"></i>
|
|
||||||
</a>-->
|
|
||||||
<span data-bind="text: messageListSearchDesc"></span>:
|
|
||||||
</div>
|
</div>
|
||||||
<div class="listDragOver" data-bind="css: {'viewAppendArea': dragOver() && '' === messageListError() && !popupVisibility(), 'dragOverEnter': dragOverEnter }, initDom: dragOverArea">
|
<div class="listDragOver" data-bind="css: {'viewAppendArea': dragOver() && '' === messageListError() && !popupVisibility(), 'dragOverEnter': dragOverEnter }, initDom: dragOverArea">
|
||||||
<i class="icon-down e-icon"></i>
|
<i class="icon-down e-icon"></i>
|
||||||
|
|
|
@ -18,15 +18,20 @@
|
||||||
<div class="dateParent actionHandle dragHandle">
|
<div class="dateParent actionHandle dragHandle">
|
||||||
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span>
|
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="threadsParent" data-bind="visible: 1 < threadsLen()">
|
||||||
|
<span class="threads-len">
|
||||||
|
<span class="threads-len-data">
|
||||||
|
<span data-bind="text: threadsLen"></span>
|
||||||
|
<i class="icon-right-mini"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div class="checkedParent">
|
<div class="checkedParent">
|
||||||
<i class="checkboxMessage" data-bind="css: checked() ? 'checkboxMessage icon-checkbox-checked' : 'checkboxMessage icon-checkbox-unchecked'"></i>
|
<i class="checkboxMessage" data-bind="css: checked() ? 'checkboxMessage icon-checkbox-checked' : 'checkboxMessage icon-checkbox-unchecked'"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="senderParent actionHandle dragHandle">
|
<div class="senderParent actionHandle dragHandle">
|
||||||
<span class="replyFlag"><i class="icon-reply"></i> </span>
|
<span class="replyFlag"><i class="icon-reply"></i> </span>
|
||||||
<span class="forwardFlag"><i class="icon-forward"></i> </span>
|
<span class="forwardFlag"><i class="icon-forward"></i> </span>
|
||||||
<span class="threads-len" data-bind="visible: 1 < threadsLen()">
|
|
||||||
<span class="threads-len-data" data-bind="text: threadsLen"></span>
|
|
||||||
</span>
|
|
||||||
<span class="sender" data-bind="text: senderEmailsString, attr: {'title': senderClearEmailsString}"></span>
|
<span class="sender" data-bind="text: senderEmailsString, attr: {'title': senderClearEmailsString}"></span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
<div class="dateParent actionHandle dragHandle">
|
<div class="dateParent actionHandle dragHandle">
|
||||||
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span>
|
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="threadsParent" data-bind="visible: 1 < threadsLen()">
|
||||||
|
<span class="threads-len">
|
||||||
|
<span class="threads-len-data">
|
||||||
|
<span data-bind="text: threadsLen"></span>
|
||||||
|
<i class="icon-right-mini"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div class="checkedParent">
|
<div class="checkedParent">
|
||||||
<i class="checkboxMessage" data-bind="css: checked() ? 'checkboxMessage icon-checkbox-checked' : 'checkboxMessage icon-checkbox-unchecked'"></i>
|
<i class="checkboxMessage" data-bind="css: checked() ? 'checkboxMessage icon-checkbox-checked' : 'checkboxMessage icon-checkbox-unchecked'"></i>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,9 +32,6 @@
|
||||||
<div class="senderParent actionHandle dragHandle">
|
<div class="senderParent actionHandle dragHandle">
|
||||||
<span class="replyFlag"><i class="icon-reply"></i> </span>
|
<span class="replyFlag"><i class="icon-reply"></i> </span>
|
||||||
<span class="forwardFlag"><i class="icon-forward"></i> </span>
|
<span class="forwardFlag"><i class="icon-forward"></i> </span>
|
||||||
<span class="threads-len" data-bind="visible: 1 < threadsLen()">
|
|
||||||
<span class="threads-len-data" data-bind="text: threadsLen"></span>
|
|
||||||
</span>
|
|
||||||
<span class="sender" data-bind="text: senderEmailsString, attr: {'title': senderClearEmailsString}"></span>
|
<span class="sender" data-bind="text: senderEmailsString, attr: {'title': senderClearEmailsString}"></span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -188,67 +188,6 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group thread-controls pull-right g-ui-user-select-none" style="margin-right: 5px"
|
|
||||||
data-bind="visible: viewThreadsControlVisibility">
|
|
||||||
|
|
||||||
<a class="btn last btn-thin pull-right" data-tooltip-join="bottom"
|
|
||||||
data-bind="command: threadBackCommand, tooltip: 'MESSAGE/BUTTON_THREAD_PREV'">
|
|
||||||
<i class="icon-right-middle"></i>
|
|
||||||
</a>
|
|
||||||
<div class="btn-group pull-right" data-bind="registrateBootstrapDropdown: true, openDropdownTrigger: threadsDropdownTrigger">
|
|
||||||
<a class="btn btn-thin btn-dark-disabled-border dropdown-toggle" id="thread-list-view-dropdown-id" data-toggle="dropdown"
|
|
||||||
href="#" tabindex="-1" data-tooltip-join="bottom"
|
|
||||||
style="margin-left: -1px; margin-right: -1px;"
|
|
||||||
data-bind="command: threadListCommand, tooltip: 'MESSAGE/BUTTON_THREAD_LIST'"
|
|
||||||
>
|
|
||||||
<i class="icon-list"
|
|
||||||
data-bind="css: {'icon-list': !messageListOfThreadsLoading(), 'icon-spinner animated': messageListOfThreadsLoading()}"></i>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu pull-right g-ui-menu thread-list"
|
|
||||||
role="menu" aria-labelledby="thread-list-view-dropdown-id"
|
|
||||||
style="min-width: 400px; max-width: 400px; width: 400px; padding: 0"
|
|
||||||
data-bind="css: {'hide-more': !viewThreadMessages.showMore() }"
|
|
||||||
>
|
|
||||||
|
|
||||||
<div data-bind="visible: '' !== viewThreadMessages.error()" style="color: red; text-align: center; padding: 10px">
|
|
||||||
<spam data-bind="text: viewThreadMessages.error"></spam>
|
|
||||||
</div>
|
|
||||||
<div data-bind="visible: messageListOfThreadsLoading" style="text-align: center; padding: 10px">
|
|
||||||
<i class="icon-spinner animated" />
|
|
||||||
</div>
|
|
||||||
<div data-bind="foreach: viewThreadMessages, visible: !messageListOfThreadsLoading()">
|
|
||||||
<li class="e-item thread-list-message real-msg" role="presentation" data-bind="css: {'selected': selected, 'more-that': $parent.viewThreadMessages.limit < $index() }">
|
|
||||||
<a class="e-link menuitem" href="#" tabindex="-1" onclick="return false;">
|
|
||||||
<span class="flagParent pull-right" style="margin-left: 5px; margin-right: 0px;">
|
|
||||||
<i class="icon-star-empty flagOff" data-bind="css: {'icon-star flagOn': flagged, 'icon-star-empty flagOff': !flagged()}"></i>
|
|
||||||
</span>
|
|
||||||
<span class="thread-date pull-right" data-moment-format="SHORT" data-bind="moment: timestamp"></span>
|
|
||||||
<div style="text-overflow: ellipsis; overflow: hidden;">
|
|
||||||
<span class="thread-from" data-bind="text: fromAsString"></span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div style="text-overflow: ellipsis; overflow: hidden;">
|
|
||||||
<span class="thread-subject" data-bind="text: subject"></span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
<div data-bind="visible: !viewThreadMessages.showMore() && !messageListOfThreadsLoading()">
|
|
||||||
<li class="e-item thread-list-message" role="presentation">
|
|
||||||
<a class="e-link menuitem more-threads" href="#" tabindex="-1"
|
|
||||||
onclick="return false"
|
|
||||||
data-i18n="MESSAGE/BUTTON_THREAD_MORE"></a>
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<a class="btn first btn-thin pull-right" data-tooltip-join="bottom"
|
|
||||||
data-bind="command: threadForwardCommand, tooltip: 'MESSAGE/BUTTON_THREAD_NEXT'">
|
|
||||||
<i class="icon-left-middle"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</nobr>
|
</nobr>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -261,9 +200,6 @@
|
||||||
<span class="flagParent">
|
<span class="flagParent">
|
||||||
<i class="icon-star-empty flagOff" data-bind="css: {'icon-star flagOn': viewIsFlagged, 'icon-star-empty flagOff': !viewIsFlagged()}"></i>
|
<i class="icon-star-empty flagOff" data-bind="css: {'icon-star flagOn': viewIsFlagged, 'icon-star-empty flagOff': !viewIsFlagged()}"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="thread-counter" data-bind="visible: viewThreadsControlVisibility"
|
|
||||||
style="font-weight: normal; margin-right: 5px">(<span
|
|
||||||
data-bind="text: viewThreadsControlDesc"></span>)</span>
|
|
||||||
<b style="color: red; margin-right: 5px" data-bind="visible: viewIsImportant">!</b>
|
<b style="color: red; margin-right: 5px" data-bind="visible: viewIsImportant">!</b>
|
||||||
<span class="subject" data-bind="text: viewSubject, title: viewSubject"></span>
|
<span class="subject" data-bind="text: viewSubject, title: viewSubject"></span>
|
||||||
<span class="i18n emptySubjectText" data-i18n="MESSAGE/EMPTY_SUBJECT_TEXT"></span>
|
<span class="i18n emptySubjectText" data-i18n="MESSAGE/EMPTY_SUBJECT_TEXT"></span>
|
||||||
|
|
Loading…
Add table
Reference in a new issue