A new way to move in message list (message focused state).

Delete/Move optimizations.
Display next message after deletion (Closes #120)
Scrolling in message view (Closes #109)
This commit is contained in:
RainLoop Team 2014-04-08 20:08:16 +04:00
parent a96e1d80c3
commit 0b30bac43f
17 changed files with 784 additions and 431 deletions

View file

@ -11,10 +11,13 @@ function RainLoopApp()
this.oData = null; this.oData = null;
this.oRemote = null; this.oRemote = null;
this.oCache = null; this.oCache = null;
this.oMoveCache = {};
this.quotaDebounce = _.debounce(this.quota, 1000 * 30); this.quotaDebounce = _.debounce(this.quota, 1000 * 30);
this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this); this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this);
this.messagesMoveTrigger = _.debounce(this.messagesMoveTrigger, 500);
window.setInterval(function () { window.setInterval(function () {
RL.pub('interval.30s'); RL.pub('interval.30s');
}, 30000); }, 30000);
@ -164,6 +167,57 @@ RainLoopApp.prototype.recacheInboxMessageList = function ()
RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true); RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true);
}; };
RainLoopApp.prototype.reloadMessageListHelper = function (bEmptyList)
{
RL.reloadMessageList(bEmptyList);
};
RainLoopApp.prototype.messagesMoveTrigger = function ()
{
var self = this;
_.each(this.oMoveCache, function (oItem) {
RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid']);
});
this.oMoveCache = {};
};
RainLoopApp.prototype.messagesMoveHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForMove)
{
var sH = '$$' + sFromFolderFullNameRaw + '$$' + sToFolderFullNameRaw + '$$';
if (!this.oMoveCache[sH])
{
this.oMoveCache[sH] = {
'From': sFromFolderFullNameRaw,
'To': sToFolderFullNameRaw,
'Uid': []
};
}
this.oMoveCache[sH]['Uid'] = _.union(this.oMoveCache[sH]['Uid'], aUidForMove);
this.messagesMoveTrigger();
};
RainLoopApp.prototype.messagesCopyHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy)
{
RL.remote().messagesCopy(
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
sToFolderFullNameRaw,
aUidForCopy
);
};
RainLoopApp.prototype.messagesDeleteHelper = function (sFromFolderFullNameRaw, aUidForRemove)
{
RL.remote().messagesDelete(
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
};
RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData) RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
{ {
if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder()) if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder())
@ -183,7 +237,7 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
} }
} }
RL.reloadMessageList(0 === RL.data().messageList().length); RL.reloadMessageListHelper(0 === RL.data().messageList().length);
RL.quotaDebounce(); RL.quotaDebounce();
} }
}; };
@ -194,12 +248,7 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
*/ */
RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove) RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove)
{ {
RL.remote().messagesDelete( this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
}; };
@ -255,25 +304,14 @@ RainLoopApp.prototype.deleteMessagesFromFolder = function (iDeleteType, sFromFol
{ {
kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () { kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () {
RL.remote().messagesDelete( self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
self.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
}]); }]);
} }
else if (oMoveFolder) else if (oMoveFolder)
{ {
RL.remote().messagesMove( this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove);
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
oMoveFolder.fullNameRaw,
aUidForRemove
);
oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw);
} }
}; };
@ -295,14 +333,14 @@ RainLoopApp.prototype.moveMessagesToFolder = function (sFromFolderFullNameRaw, a
if (oFromFolder && oToFolder) if (oFromFolder && oToFolder)
{ {
bCopy = Utils.isUnd(bCopy) ? false : !!bCopy; if (Utils.isUnd(bCopy) ? false : !!bCopy)
{
RL.remote()[bCopy ? 'messagesCopy' : 'messagesMove']( this.messagesCopyHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
this.moveOrDeleteResponseHelper, }
oFromFolder.fullNameRaw, else
oToFolder.fullNameRaw, {
aUidForMove this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
); }
RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy);
return true; return true;

View file

@ -137,6 +137,7 @@ Enums.EventKeyCode = {
'Down': 40, 'Down': 40,
'End': 35, 'End': 35,
'Home': 36, 'Home': 36,
'Space': 32,
'Insert': 45, 'Insert': 45,
'Delete': 46, 'Delete': 46,
'A': 65, 'A': 65,

View file

@ -3,16 +3,35 @@
/** /**
* @constructor * @constructor
* @param {koProperty} oKoList * @param {koProperty} oKoList
* @param {koProperty} oKoFocusedItem
* @param {koProperty} oKoSelectedItem * @param {koProperty} oKoSelectedItem
* @param {string} sItemSelector * @param {string} sItemSelector
* @param {string} sItemSelectedSelector * @param {string} sItemSelectedSelector
* @param {string} sItemCheckedSelector * @param {string} sItemCheckedSelector
* @param {string} sItemFocusedSelector
*/ */
function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector, sItemCheckedSelector) function Selector(oKoList, oKoFocusedItem, oKoSelectedItem,
sItemSelector, sItemSelectedSelector, sItemCheckedSelector, sItemFocusedSelector)
{ {
this.list = oKoList; this.list = oKoList;
this.focusedItem = oKoFocusedItem;
this.selectedItem = oKoSelectedItem; this.selectedItem = oKoSelectedItem;
this.focusedItem.extend({'toggleSubscribe': [null,
function (oPrev) {
if (oPrev)
{
oPrev.focused(false);
}
}, function (oNext) {
if (oNext)
{
oNext.focused(true);
}
}
]});
this.selectedItem.extend({'toggleSubscribe': [null, this.selectedItem.extend({'toggleSubscribe': [null,
function (oPrev) { function (oPrev) {
if (oPrev) if (oPrev)
@ -33,29 +52,38 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
this.sItemSelector = sItemSelector; this.sItemSelector = sItemSelector;
this.sItemSelectedSelector = sItemSelectedSelector; this.sItemSelectedSelector = sItemSelectedSelector;
this.sItemCheckedSelector = sItemCheckedSelector; this.sItemCheckedSelector = sItemCheckedSelector;
this.sItemFocusedSelector = sItemFocusedSelector;
this.sLastUid = ''; this.sLastUid = '';
this.oCallbacks = {}; this.oCallbacks = {};
this.iSelectTimer = 0; this.iSelectTimer = 0;
this.bUseKeyboard = true; this.bUseKeyboard = true;
this.bAutoSelect = true;
this.emptyFunction = function () {}; this.emptyFunction = function () {};
this.useItemSelectCallback = true; this.useItemSelectCallback = true;
this.throttleSelection = false;
this.selectedItem.subscribe(function (oItem) { this.selectedItem.subscribe(function (oItem) {
if (this.useItemSelectCallback)
if (oItem)
{ {
if (this.throttleSelection) this.sLastUid = this.getItemUid(oItem);
{ this.focusedItem(oItem);
this.throttleSelection = false;
this.selectItemCallbacksThrottle(oItem);
} }
else
if (this.useItemSelectCallback)
{ {
this.selectItemCallbacks(oItem); this.selectItemCallbacks(oItem);
} }
}, this);
this.focusedItem.subscribe(function (oItem) {
if (oItem)
{
this.sLastUid = this.getItemUid(oItem);
} }
}, this); }, this);
@ -87,25 +115,43 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
this.useItemSelectCallback = false; this.useItemSelectCallback = false;
var
self = this,
iLen = 0,
sFocusedUid = this.focusedItem() ? this.getItemUid(this.focusedItem()) : ''
;
this.selectedItem(null); this.selectedItem(null);
this.focusedItem(null);
if (Utils.isArray(aItems)) if (Utils.isArray(aItems))
{ {
var self = this, iLen = aCheckedCache.length; iLen = aCheckedCache.length;
_.each(aItems, function (oItem) { _.each(aItems, function (oItem) {
if (0 < iLen && -1 < Utils.inArray(self.getItemUid(oItem), aCheckedCache))
var sUid = self.getItemUid(oItem);
if (0 < iLen && -1 < Utils.inArray(sUid, aCheckedCache))
{ {
oItem.checked(true); oItem.checked(true);
iLen--; iLen--;
} }
if ('' !== sFocusedUid && sUid === sFocusedUid)
{
self.focusedItem(oItem);
}
if (null !== mSelected && mSelected === self.getItemUid(oItem)) if (null !== mSelected && mSelected === self.getItemUid(oItem))
{ {
oItem.selected(true); if (!oItem.selected())
mSelected = null; {
self.selectedItem(oItem); self.selectedItem(oItem);
} }
mSelected = null;
}
}); });
} }
@ -113,6 +159,7 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
aCheckedCache = []; aCheckedCache = [];
mSelected = null; mSelected = null;
}, this); }, this);
this.list.setSelectedByUid = function (sUid) { this.list.setSelectedByUid = function (sUid) {
@ -185,14 +232,23 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
}) })
; ;
key('space, enter', sKeyScope, function () { key('enter', sKeyScope, function () {
if (!self.bAutoSelect)
{
if (self.focusedItem())
{
self.actionClick(self.focusedItem());
}
return false; return false;
}
}); });
key('up, shift+up, down, shift+down, insert, home, end, pageup, pagedown', sKeyScope, function (event, handler) { key('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', sKeyScope, function (event, handler) {
if (event && handler && handler.shortcut) if (event && handler && handler.shortcut)
{ {
var iKey = 0, aCodes = null; // TODO
var iKey = 0;
switch (handler.shortcut) switch (handler.shortcut)
{ {
case 'up': case 'up':
@ -204,15 +260,22 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
iKey = Enums.EventKeyCode.Down; iKey = Enums.EventKeyCode.Down;
break; break;
case 'insert': case 'insert':
iKey = Enums.EventKeyCode.Insert;
break;
case 'space':
iKey = Enums.EventKeyCode.Space;
break;
case 'home': case 'home':
iKey = Enums.EventKeyCode.Home;
break;
case 'end': case 'end':
iKey = Enums.EventKeyCode.End;
break;
case 'pageup': case 'pageup':
iKey = Enums.EventKeyCode.PageUp;
break;
case 'pagedown': case 'pagedown':
aCodes = key.getPressedKeyCodes(); iKey = Enums.EventKeyCode.PageDown;
if (aCodes && aCodes[0])
{
iKey = aCodes[0];
}
break; break;
} }
@ -250,6 +313,11 @@ Selector.prototype.useKeyboard = function (bValue)
this.bUseKeyboard = !!bValue; this.bUseKeyboard = !!bValue;
}; };
Selector.prototype.autoSelect = function (bValue)
{
this.bAutoSelect = !!bValue;
};
/** /**
* @param {Object} oItem * @param {Object} oItem
* @returns {string} * @returns {string}
@ -284,14 +352,14 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
oResult = null, oResult = null,
aList = this.list(), aList = this.list(),
iListLen = aList ? aList.length : 0, iListLen = aList ? aList.length : 0,
oSelected = this.selectedItem() oFocused = this.focusedItem()
; ;
if (0 < iListLen) if (0 < iListLen)
{ {
if (!oSelected) if (!oFocused)
{ {
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.PageUp === iEventKeyCode) if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode || Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.PageUp === iEventKeyCode)
{ {
oResult = aList[0]; oResult = aList[0];
} }
@ -300,16 +368,16 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
oResult = aList[aList.length - 1]; oResult = aList[aList.length - 1];
} }
} }
else if (oSelected) else if (oFocused)
{ {
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode) if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
_.each(aList, function (oItem) { _.each(aList, function (oItem) {
if (!bStop) if (!bStop)
{ {
switch (iEventKeyCode) { switch (iEventKeyCode) {
case Enums.EventKeyCode.Up: case Enums.EventKeyCode.Up:
if (oSelected === oItem) if (oFocused === oItem)
{ {
bStop = true; bStop = true;
} }
@ -320,12 +388,13 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
break; break;
case Enums.EventKeyCode.Down: case Enums.EventKeyCode.Down:
case Enums.EventKeyCode.Insert: case Enums.EventKeyCode.Insert:
case Enums.EventKeyCode.Space:
if (bNext) if (bNext)
{ {
oResult = oItem; oResult = oItem;
bStop = true; bStop = true;
} }
else if (oSelected === oItem) else if (oFocused === oItem)
{ {
bNext = true; bNext = true;
} }
@ -349,7 +418,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
{ {
for (; iIndex < iListLen; iIndex++) for (; iIndex < iListLen; iIndex++)
{ {
if (oSelected === aList[iIndex]) if (oFocused === aList[iIndex])
{ {
iIndex += iPageStep; iIndex += iPageStep;
iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex; iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex;
@ -362,7 +431,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
{ {
for (iIndex = iListLen; iIndex >= 0; iIndex--) for (iIndex = iListLen; iIndex >= 0; iIndex--)
{ {
if (oSelected === aList[iIndex]) if (oFocused === aList[iIndex])
{ {
iIndex -= iPageStep; iIndex -= iPageStep;
iIndex = 0 > iIndex ? 0 : iIndex; iIndex = 0 > iIndex ? 0 : iIndex;
@ -376,53 +445,43 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
if (oResult) if (oResult)
{ {
if (oSelected) if (oFocused)
{ {
if (bShiftKey) if (bShiftKey)
{ {
if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode) if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
else if (Enums.EventKeyCode.Insert === iEventKeyCode) else if (Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
this.throttleSelection = true; this.focusedItem(oResult);
this.selectedItem(oResult);
this.throttleSelection = true;
if (0 !== this.iSelectTimer) if (this.bAutoSelect && Enums.EventKeyCode.Space !== iEventKeyCode)
{ {
window.clearTimeout(this.iSelectTimer); window.clearTimeout(this.iSelectTimer);
this.iSelectTimer = window.setTimeout(function () { this.iSelectTimer = window.setTimeout(function () {
self.iSelectTimer = 0; self.iSelectTimer = 0;
self.actionClick(oResult); self.actionClick(oResult);
}, 1000); }, 300);
}
else
{
this.iSelectTimer = window.setTimeout(function () {
self.iSelectTimer = 0;
}, 200);
this.actionClick(oResult);
} }
this.scrollToSelected(); this.scrollToFocused();
} }
else if (oSelected) else if (oFocused)
{ {
if (bShiftKey && (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode)) if (bShiftKey && (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode))
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
else if (Enums.EventKeyCode.Insert === iEventKeyCode) else if (Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
}; };
@ -430,7 +489,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
/** /**
* @return {boolean} * @return {boolean}
*/ */
Selector.prototype.scrollToSelected = function () Selector.prototype.scrollToFocused = function ()
{ {
if (!this.oContentVisible || !this.oContentScrollable) if (!this.oContentVisible || !this.oContentScrollable)
{ {
@ -439,13 +498,13 @@ Selector.prototype.scrollToSelected = function ()
var var
iOffset = 20, iOffset = 20,
oSelected = $(this.sItemSelectedSelector, this.oContentScrollable), oFocused = $(this.sItemFocusedSelector, this.oContentScrollable),
oPos = oSelected.position(), oPos = oFocused.position(),
iVisibleHeight = this.oContentVisible.height(), iVisibleHeight = this.oContentVisible.height(),
iSelectedHeight = oSelected.outerHeight() iFocusedHeight = oFocused.outerHeight()
; ;
if (oPos && (oPos.top < 0 || oPos.top + iSelectedHeight > iVisibleHeight)) if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight))
{ {
if (oPos.top < 0) if (oPos.top < 0)
{ {
@ -453,7 +512,7 @@ Selector.prototype.scrollToSelected = function ()
} }
else else
{ {
this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iSelectedHeight + iOffset); this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iFocusedHeight + iOffset);
} }
return true; return true;
@ -511,7 +570,6 @@ Selector.prototype.eventClickFunction = function (oItem, oEvent)
}; };
/** /**
*
* @param {Object} oItem * @param {Object} oItem
* @param {Object=} oEvent * @param {Object=} oEvent
*/ */
@ -535,6 +593,7 @@ Selector.prototype.actionClick = function (oItem, oEvent)
} }
oItem.checked(!oItem.checked()); oItem.checked(!oItem.checked());
this.eventClickFunction(oItem, oEvent); this.eventClickFunction(oItem, oEvent);
} }
else if (oEvent.ctrlKey) else if (oEvent.ctrlKey)
@ -549,7 +608,6 @@ Selector.prototype.actionClick = function (oItem, oEvent)
if (bClick) if (bClick)
{ {
this.selectedItem(oItem); this.selectedItem(oItem);
this.sLastUid = sUid;
} }
} }
}; };

View file

@ -584,7 +584,7 @@ WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder,
'FromFolder': sFolder, 'FromFolder': sFolder,
'ToFolder': sToFolder, 'ToFolder': sToFolder,
'Uids': aUids.join(',') 'Uids': aUids.join(',')
}, null, '', ['MessageList', 'Message']); }, null, '', ['MessageList']);
}; };
/** /**
@ -612,7 +612,7 @@ WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder
this.defaultRequest(fCallback, 'MessageDelete', { this.defaultRequest(fCallback, 'MessageDelete', {
'Folder': sFolder, 'Folder': sFolder,
'Uids': aUids.join(',') 'Uids': aUids.join(',')
}, null, '', ['MessageList', 'Message']); }, null, '', ['MessageList']);
}; };
/** /**

View file

@ -297,6 +297,7 @@ function WebMailDataStorage()
}, this); }, this);
this.currentMessage = ko.observable(null); this.currentMessage = ko.observable(null);
this.currentFocusedMessage = ko.observable(null);
this.message.subscribe(function (oMessage) { this.message.subscribe(function (oMessage) {
if (null === oMessage) if (null === oMessage)
@ -778,11 +779,15 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
iUnseenCount = 0, iUnseenCount = 0,
oData = RL.data(), oData = RL.data(),
oCache = RL.cache(), oCache = RL.cache(),
bMoveSelected = false,
bGetNext = false,
oNextMessage = null,
aMessageList = oData.messageList(),
oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw), oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw),
oToFolder = '' === sToFolderFullNameRaw ? null : oCache.getFolderFromCacheList(sToFolderFullNameRaw || ''), oToFolder = '' === sToFolderFullNameRaw ? null : oCache.getFolderFromCacheList(sToFolderFullNameRaw || ''),
sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(), sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(),
oCurrentMessage = oData.message(), oCurrentMessage = oData.message(),
aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(oData.messageList(), function (oMessage) { aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function (oMessage) {
return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove); return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove);
}) : [] }) : []
; ;
@ -792,6 +797,11 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
{ {
iUnseenCount++; iUnseenCount++;
} }
if (oMessage.selected())
{
bMoveSelected = true;
}
}); });
if (oFromFolder && !bCopy) if (oFromFolder && !bCopy)
@ -827,10 +837,33 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
} }
else else
{ {
// select next message
if (bMoveSelected)
{
_.each(aMessageList, function (oMessage) {
if (!oNextMessage && oMessage)
{
if (bGetNext && !oMessage.checked() && !oMessage.deleted() && !oMessage.selected())
{
oNextMessage = oMessage;
}
else if (!bGetNext && oMessage.selected())
{
bGetNext = true;
}
}
});
if (oNextMessage)
{
this.currentMessage(oNextMessage);
}
}
oData.messageListIsNotCompleted(true); oData.messageListIsNotCompleted(true);
_.each(aMessages, function (oMessage) { _.each(aMessages, function (oMessage) {
if (oCurrentMessage && oCurrentMessage.requestHash === oMessage.requestHash) if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash)
{ {
oCurrentMessage = null; oCurrentMessage = null;
oData.message(null); oData.message(null);

View file

@ -161,6 +161,10 @@
height: 100%; height: 100%;
} }
&.focused .sidebarParent {
background-color: #aaa;
}
&.deleted { &.deleted {
max-height: 0px; max-height: 0px;
border-color: transparent !important; border-color: transparent !important;
@ -213,15 +217,24 @@
.sidebarParent { .sidebarParent {
background-color: #69A8F5; background-color: #69A8F5;
} }
&.focused .sidebarParent {
background-color: darken(#69A8F5, 5%) !important;
}
} }
&.selected { &.selected {
background-color: #fff; background-color: #fff;
z-index: 102; z-index: 102;
.sidebarParent { .sidebarParent {
background-color: #398CF2; background-color: #398CF2;
} }
&.focused .sidebarParent {
background-color: darken(#398CF2, 5%) !important;
}
} }
} }
} }

View file

@ -229,6 +229,10 @@ html.rl-no-preview-pane {
height: 100%; height: 100%;
} }
&.focused .sidebarParent {
background-color: #aaa !important;
}
&.e-single-line { &.e-single-line {
height: 35px; height: 35px;
} }
@ -409,6 +413,10 @@ html.rl-no-preview-pane {
.sidebarParent { .sidebarParent {
background-color: orange; background-color: orange;
} }
&.focused .sidebarParent {
background-color: darken(orange, 10%) !important;
}
} }
&.hasUnseenSubMessage { &.hasUnseenSubMessage {
@ -416,6 +424,9 @@ html.rl-no-preview-pane {
.sidebarParent { .sidebarParent {
background-color: lighten(orange, 30%); background-color: lighten(orange, 30%);
} }
&.focused .sidebarParent {
background-color: darken(orange, 10%) !important;
}
} }
&.hasParentMessage { &.hasParentMessage {
@ -425,11 +436,20 @@ html.rl-no-preview-pane {
background-color: #bdc3c7; background-color: #bdc3c7;
} }
&.focused .sidebarParent {
background-color: darken(#bdc3c7, 10%) !important;
}
&.unseen { &.unseen {
background-color: darken(#ecf0f1, 5%); background-color: darken(#ecf0f1, 5%);
.sidebarParent { .sidebarParent {
background-color: darken(#bdc3c7, 30%); background-color: darken(#bdc3c7, 30%);
} }
&.focused .sidebarParent {
background-color: darken(#bdc3c7, 40%) !important;
}
} }
} }
@ -437,6 +457,10 @@ html.rl-no-preview-pane {
.sidebarParent { .sidebarParent {
background-color: lighten(#398CF2, 10%) !important; background-color: lighten(#398CF2, 10%) !important;
} }
&.focused .sidebarParent {
background-color: darken(#398CF2, 5%) !important;
}
} }
&.selected { &.selected {
@ -447,6 +471,10 @@ html.rl-no-preview-pane {
background-color: #398CF2 !important; background-color: #398CF2 !important;
} }
&.focused .sidebarParent {
background-color: darken(#398CF2, 5%) !important;
}
.delimiter { .delimiter {
background-color: #398CF2; background-color: #398CF2;
.opacity(20); .opacity(20);
@ -483,7 +511,7 @@ html.rl-no-preview-pane {
background-color: #000; background-color: #000;
} }
.b-content { .b-content {
.opacity(98); .opacity(97);
} }
} }

View file

@ -19,6 +19,7 @@ function MailBoxMessageListViewModel()
this.message = oData.message; this.message = oData.message;
this.messageList = oData.messageList; this.messageList = oData.messageList;
this.currentMessage = oData.currentMessage; this.currentMessage = oData.currentMessage;
this.currentFocusedMessage = oData.currentFocusedMessage;
this.isMessageSelected = oData.isMessageSelected; this.isMessageSelected = oData.isMessageSelected;
this.messageListSearch = oData.messageListSearch; this.messageListSearch = oData.messageListSearch;
this.messageListError = oData.messageListError; this.messageListError = oData.messageListError;
@ -191,8 +192,9 @@ function MailBoxMessageListViewModel()
this.quotaTooltip = _.bind(this.quotaTooltip, this); this.quotaTooltip = _.bind(this.quotaTooltip, this);
this.selector = new Selector(this.messageList, this.currentMessage, this.selector = new Selector(this.messageList, this.currentFocusedMessage, this.currentMessage,
'.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage'); '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage',
'.messageListItem.focused');
this.selector.on('onItemSelect', _.bind(function (oMessage) { this.selector.on('onItemSelect', _.bind(function (oMessage) {
if (oMessage) if (oMessage)
@ -215,6 +217,13 @@ function MailBoxMessageListViewModel()
return oMessage ? oMessage.generateUid() : ''; return oMessage ? oMessage.generateUid() : '';
}); });
// this.selector.autoSelect(false);
oData.layout.subscribe(function (mValue) {
this.selector.autoSelect(Enums.Layout.NoPreview !== mValue);
}, this);
oData.layout.valueHasMutated();
RL RL
.sub('mailbox.message-list.selector.go-down', function () { .sub('mailbox.message-list.selector.go-down', function () {
this.selector.goDown(); this.selector.goDown();
@ -687,7 +696,7 @@ MailBoxMessageListViewModel.prototype.initShortcuts = function ()
}); });
// change focused state // change focused state
key('tab, enter', Enums.KeyState.MessageList, function () { key('tab', Enums.KeyState.MessageList, function () {
if (oData.useKeyboardShortcuts()) if (oData.useKeyboardShortcuts())
{ {
if (self.message()) if (self.message())

View file

@ -385,12 +385,11 @@ MailBoxMessageViewViewModel.prototype.escShortcuts = function ()
else else
{ {
this.message.focused(false); this.message.focused(false);
}
if (Enums.Layout.NoPreview === RL.data().layout()) if (Enums.Layout.NoPreview === RL.data().layout())
{ {
RL.historyBack(); RL.historyBack();
} }
}
return false; return false;
} }
@ -493,7 +492,6 @@ MailBoxMessageViewViewModel.prototype.initShortcuts = function ()
key('delete, shift+delete', Enums.KeyState.MessageView, function (event, handler) { key('delete, shift+delete', Enums.KeyState.MessageView, function (event, handler) {
if (oData.useKeyboardShortcuts() && event) if (oData.useKeyboardShortcuts() && event)
{ {
self.deleteCommand();
if (handler && 'shift+delete' === handler.shortcut) if (handler && 'shift+delete' === handler.shortcut)
{ {
self.deleteWithoutMoveCommand(); self.deleteWithoutMoveCommand();

View file

@ -33,7 +33,9 @@ function PopupsContactsViewModel()
this.contacts = ko.observableArray([]); this.contacts = ko.observableArray([]);
this.contacts.loading = ko.observable(false).extend({'throttle': 200}); this.contacts.loading = ko.observable(false).extend({'throttle': 200});
this.contacts.importing = ko.observable(false).extend({'throttle': 200}); this.contacts.importing = ko.observable(false).extend({'throttle': 200});
this.currentContact = ko.observable(null); this.currentContact = ko.observable(null);
this.currentFocusedContact = ko.observable(null);
this.importUploaderButton = ko.observable(null); this.importUploaderButton = ko.observable(null);
@ -160,8 +162,9 @@ function PopupsContactsViewModel()
}); });
}, this); }, this);
this.selector = new Selector(this.contacts, this.currentContact, this.selector = new Selector(this.contacts, this.currentFocusedContact, this.currentContact,
'.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem'); '.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem',
'.e-contact-item.focused');
this.selector.on('onItemSelect', _.bind(function (oContact) { this.selector.on('onItemSelect', _.bind(function (oContact) {
this.populateViewContact(oContact ? oContact : null); this.populateViewContact(oContact ? oContact : null);

View file

@ -6843,6 +6843,9 @@ html.rl-no-preview-pane .messageList.message-selected {
float: left; float: left;
height: 100%; height: 100%;
} }
.messageList .b-content .messageListItem.focused .sidebarParent {
background-color: #aaa !important;
}
.messageList .b-content .messageListItem.e-single-line { .messageList .b-content .messageListItem.e-single-line {
height: 35px; height: 35px;
} }
@ -6999,27 +7002,42 @@ html.rl-no-preview-pane .messageList.message-selected {
.messageList .b-content .messageListItem.unseen .sidebarParent { .messageList .b-content .messageListItem.unseen .sidebarParent {
background-color: orange; background-color: orange;
} }
.messageList .b-content .messageListItem.unseen.focused .sidebarParent {
background-color: #cc8400 !important;
}
.messageList .b-content .messageListItem.hasUnseenSubMessage { .messageList .b-content .messageListItem.hasUnseenSubMessage {
background-color: #FFFFD9; background-color: #FFFFD9;
} }
.messageList .b-content .messageListItem.hasUnseenSubMessage .sidebarParent { .messageList .b-content .messageListItem.hasUnseenSubMessage .sidebarParent {
background-color: #ffdb99; background-color: #ffdb99;
} }
.messageList .b-content .messageListItem.hasUnseenSubMessage.focused .sidebarParent {
background-color: #cc8400 !important;
}
.messageList .b-content .messageListItem.hasParentMessage { .messageList .b-content .messageListItem.hasParentMessage {
background-color: #ecf0f1; background-color: #ecf0f1;
} }
.messageList .b-content .messageListItem.hasParentMessage .sidebarParent { .messageList .b-content .messageListItem.hasParentMessage .sidebarParent {
background-color: #bdc3c7; background-color: #bdc3c7;
} }
.messageList .b-content .messageListItem.hasParentMessage.focused .sidebarParent {
background-color: #a1aab0 !important;
}
.messageList .b-content .messageListItem.hasParentMessage.unseen { .messageList .b-content .messageListItem.hasParentMessage.unseen {
background-color: #dde4e6; background-color: #dde4e6;
} }
.messageList .b-content .messageListItem.hasParentMessage.unseen .sidebarParent { .messageList .b-content .messageListItem.hasParentMessage.unseen .sidebarParent {
background-color: #6c777f; background-color: #6c777f;
} }
.messageList .b-content .messageListItem.hasParentMessage.unseen.focused .sidebarParent {
background-color: #545e64 !important;
}
.messageList .b-content .messageListItem.checked .sidebarParent { .messageList .b-content .messageListItem.checked .sidebarParent {
background-color: #69a8f5 !important; background-color: #69a8f5 !important;
} }
.messageList .b-content .messageListItem.checked.focused .sidebarParent {
background-color: #217ef0 !important;
}
.messageList .b-content .messageListItem.selected { .messageList .b-content .messageListItem.selected {
background-color: #DFEFFF; background-color: #DFEFFF;
z-index: 102; z-index: 102;
@ -7027,6 +7045,9 @@ html.rl-no-preview-pane .messageList.message-selected {
.messageList .b-content .messageListItem.selected .sidebarParent { .messageList .b-content .messageListItem.selected .sidebarParent {
background-color: #398CF2 !important; background-color: #398CF2 !important;
} }
.messageList .b-content .messageListItem.selected.focused .sidebarParent {
background-color: #217ef0 !important;
}
.messageList .b-content .messageListItem.selected .delimiter { .messageList .b-content .messageListItem.selected .delimiter {
background-color: #398CF2; background-color: #398CF2;
opacity: 0.2; opacity: 0.2;
@ -7055,8 +7076,8 @@ html.rl-no-preview-pane .messageList.message-selected {
background-color: #000; background-color: #000;
} }
.messageList.message-focused .b-content { .messageList.message-focused .b-content {
opacity: 0.98; opacity: 0.97;
filter: alpha(opacity=98); filter: alpha(opacity=97);
} }
.messageList.hideMessageListCheckbox .checkedParent, .messageList.hideMessageListCheckbox .checkedParent,
.messageList.hideMessageListCheckbox .checkboxCkeckAll { .messageList.hideMessageListCheckbox .checkboxCkeckAll {
@ -7595,6 +7616,9 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
float: left; float: left;
height: 100%; height: 100%;
} }
.b-contacts-content.modal .b-list-content .e-contact-item.focused .sidebarParent {
background-color: #aaa;
}
.b-contacts-content.modal .b-list-content .e-contact-item.deleted { .b-contacts-content.modal .b-list-content .e-contact-item.deleted {
max-height: 0px; max-height: 0px;
border-color: transparent !important; border-color: transparent !important;
@ -7641,6 +7665,9 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
.b-contacts-content.modal .b-list-content .e-contact-item.checked .sidebarParent { .b-contacts-content.modal .b-list-content .e-contact-item.checked .sidebarParent {
background-color: #69A8F5; background-color: #69A8F5;
} }
.b-contacts-content.modal .b-list-content .e-contact-item.checked.focused .sidebarParent {
background-color: #519af3 !important;
}
.b-contacts-content.modal .b-list-content .e-contact-item.selected { .b-contacts-content.modal .b-list-content .e-contact-item.selected {
background-color: #fff; background-color: #fff;
z-index: 102; z-index: 102;
@ -7648,6 +7675,9 @@ html.rl-message-fullscreen .messageView .b-content .buttonFull {
.b-contacts-content.modal .b-list-content .e-contact-item.selected .sidebarParent { .b-contacts-content.modal .b-list-content .e-contact-item.selected .sidebarParent {
background-color: #398CF2; background-color: #398CF2;
} }
.b-contacts-content.modal .b-list-content .e-contact-item.selected.focused .sidebarParent {
background-color: #217ef0 !important;
}
.b-contacts-content.modal .b-view-content { .b-contacts-content.modal .b-view-content {
position: absolute; position: absolute;
top: 0; top: 0;

File diff suppressed because one or more lines are too long

View file

@ -477,6 +477,7 @@ Enums.EventKeyCode = {
'Down': 40, 'Down': 40,
'End': 35, 'End': 35,
'Home': 36, 'Home': 36,
'Space': 32,
'Insert': 45, 'Insert': 45,
'Delete': 46, 'Delete': 46,
'A': 65, 'A': 65,

File diff suppressed because one or more lines are too long

View file

@ -481,6 +481,7 @@ Enums.EventKeyCode = {
'Down': 40, 'Down': 40,
'End': 35, 'End': 35,
'Home': 36, 'Home': 36,
'Space': 32,
'Insert': 45, 'Insert': 45,
'Delete': 46, 'Delete': 46,
'A': 65, 'A': 65,
@ -3886,16 +3887,35 @@ NewHtmlEditorWrapper.prototype.clear = function (bFocus)
/** /**
* @constructor * @constructor
* @param {koProperty} oKoList * @param {koProperty} oKoList
* @param {koProperty} oKoFocusedItem
* @param {koProperty} oKoSelectedItem * @param {koProperty} oKoSelectedItem
* @param {string} sItemSelector * @param {string} sItemSelector
* @param {string} sItemSelectedSelector * @param {string} sItemSelectedSelector
* @param {string} sItemCheckedSelector * @param {string} sItemCheckedSelector
* @param {string} sItemFocusedSelector
*/ */
function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector, sItemCheckedSelector) function Selector(oKoList, oKoFocusedItem, oKoSelectedItem,
sItemSelector, sItemSelectedSelector, sItemCheckedSelector, sItemFocusedSelector)
{ {
this.list = oKoList; this.list = oKoList;
this.focusedItem = oKoFocusedItem;
this.selectedItem = oKoSelectedItem; this.selectedItem = oKoSelectedItem;
this.focusedItem.extend({'toggleSubscribe': [null,
function (oPrev) {
if (oPrev)
{
oPrev.focused(false);
}
}, function (oNext) {
if (oNext)
{
oNext.focused(true);
}
}
]});
this.selectedItem.extend({'toggleSubscribe': [null, this.selectedItem.extend({'toggleSubscribe': [null,
function (oPrev) { function (oPrev) {
if (oPrev) if (oPrev)
@ -3916,29 +3936,38 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
this.sItemSelector = sItemSelector; this.sItemSelector = sItemSelector;
this.sItemSelectedSelector = sItemSelectedSelector; this.sItemSelectedSelector = sItemSelectedSelector;
this.sItemCheckedSelector = sItemCheckedSelector; this.sItemCheckedSelector = sItemCheckedSelector;
this.sItemFocusedSelector = sItemFocusedSelector;
this.sLastUid = ''; this.sLastUid = '';
this.oCallbacks = {}; this.oCallbacks = {};
this.iSelectTimer = 0; this.iSelectTimer = 0;
this.bUseKeyboard = true; this.bUseKeyboard = true;
this.bAutoSelect = true;
this.emptyFunction = function () {}; this.emptyFunction = function () {};
this.useItemSelectCallback = true; this.useItemSelectCallback = true;
this.throttleSelection = false;
this.selectedItem.subscribe(function (oItem) { this.selectedItem.subscribe(function (oItem) {
if (this.useItemSelectCallback)
if (oItem)
{ {
if (this.throttleSelection) this.sLastUid = this.getItemUid(oItem);
{ this.focusedItem(oItem);
this.throttleSelection = false;
this.selectItemCallbacksThrottle(oItem);
} }
else
if (this.useItemSelectCallback)
{ {
this.selectItemCallbacks(oItem); this.selectItemCallbacks(oItem);
} }
}, this);
this.focusedItem.subscribe(function (oItem) {
if (oItem)
{
this.sLastUid = this.getItemUid(oItem);
} }
}, this); }, this);
@ -3970,25 +3999,43 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
this.useItemSelectCallback = false; this.useItemSelectCallback = false;
var
self = this,
iLen = 0,
sFocusedUid = this.focusedItem() ? this.getItemUid(this.focusedItem()) : ''
;
this.selectedItem(null); this.selectedItem(null);
this.focusedItem(null);
if (Utils.isArray(aItems)) if (Utils.isArray(aItems))
{ {
var self = this, iLen = aCheckedCache.length; iLen = aCheckedCache.length;
_.each(aItems, function (oItem) { _.each(aItems, function (oItem) {
if (0 < iLen && -1 < Utils.inArray(self.getItemUid(oItem), aCheckedCache))
var sUid = self.getItemUid(oItem);
if (0 < iLen && -1 < Utils.inArray(sUid, aCheckedCache))
{ {
oItem.checked(true); oItem.checked(true);
iLen--; iLen--;
} }
if ('' !== sFocusedUid && sUid === sFocusedUid)
{
self.focusedItem(oItem);
}
if (null !== mSelected && mSelected === self.getItemUid(oItem)) if (null !== mSelected && mSelected === self.getItemUid(oItem))
{ {
oItem.selected(true); if (!oItem.selected())
mSelected = null; {
self.selectedItem(oItem); self.selectedItem(oItem);
} }
mSelected = null;
}
}); });
} }
@ -3996,6 +4043,7 @@ function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector
aCheckedCache = []; aCheckedCache = [];
mSelected = null; mSelected = null;
}, this); }, this);
this.list.setSelectedByUid = function (sUid) { this.list.setSelectedByUid = function (sUid) {
@ -4068,14 +4116,23 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
}) })
; ;
key('space, enter', sKeyScope, function () { key('enter', sKeyScope, function () {
if (!self.bAutoSelect)
{
if (self.focusedItem())
{
self.actionClick(self.focusedItem());
}
return false; return false;
}
}); });
key('up, shift+up, down, shift+down, insert, home, end, pageup, pagedown', sKeyScope, function (event, handler) { key('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', sKeyScope, function (event, handler) {
if (event && handler && handler.shortcut) if (event && handler && handler.shortcut)
{ {
var iKey = 0, aCodes = null; // TODO
var iKey = 0;
switch (handler.shortcut) switch (handler.shortcut)
{ {
case 'up': case 'up':
@ -4087,15 +4144,22 @@ Selector.prototype.init = function (oContentVisible, oContentScrollable, sKeySco
iKey = Enums.EventKeyCode.Down; iKey = Enums.EventKeyCode.Down;
break; break;
case 'insert': case 'insert':
iKey = Enums.EventKeyCode.Insert;
break;
case 'space':
iKey = Enums.EventKeyCode.Space;
break;
case 'home': case 'home':
iKey = Enums.EventKeyCode.Home;
break;
case 'end': case 'end':
iKey = Enums.EventKeyCode.End;
break;
case 'pageup': case 'pageup':
iKey = Enums.EventKeyCode.PageUp;
break;
case 'pagedown': case 'pagedown':
aCodes = key.getPressedKeyCodes(); iKey = Enums.EventKeyCode.PageDown;
if (aCodes && aCodes[0])
{
iKey = aCodes[0];
}
break; break;
} }
@ -4133,6 +4197,11 @@ Selector.prototype.useKeyboard = function (bValue)
this.bUseKeyboard = !!bValue; this.bUseKeyboard = !!bValue;
}; };
Selector.prototype.autoSelect = function (bValue)
{
this.bAutoSelect = !!bValue;
};
/** /**
* @param {Object} oItem * @param {Object} oItem
* @returns {string} * @returns {string}
@ -4167,14 +4236,14 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
oResult = null, oResult = null,
aList = this.list(), aList = this.list(),
iListLen = aList ? aList.length : 0, iListLen = aList ? aList.length : 0,
oSelected = this.selectedItem() oFocused = this.focusedItem()
; ;
if (0 < iListLen) if (0 < iListLen)
{ {
if (!oSelected) if (!oFocused)
{ {
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.PageUp === iEventKeyCode) if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode || Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.PageUp === iEventKeyCode)
{ {
oResult = aList[0]; oResult = aList[0];
} }
@ -4183,16 +4252,16 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
oResult = aList[aList.length - 1]; oResult = aList[aList.length - 1];
} }
} }
else if (oSelected) else if (oFocused)
{ {
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode) if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
_.each(aList, function (oItem) { _.each(aList, function (oItem) {
if (!bStop) if (!bStop)
{ {
switch (iEventKeyCode) { switch (iEventKeyCode) {
case Enums.EventKeyCode.Up: case Enums.EventKeyCode.Up:
if (oSelected === oItem) if (oFocused === oItem)
{ {
bStop = true; bStop = true;
} }
@ -4203,12 +4272,13 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
break; break;
case Enums.EventKeyCode.Down: case Enums.EventKeyCode.Down:
case Enums.EventKeyCode.Insert: case Enums.EventKeyCode.Insert:
case Enums.EventKeyCode.Space:
if (bNext) if (bNext)
{ {
oResult = oItem; oResult = oItem;
bStop = true; bStop = true;
} }
else if (oSelected === oItem) else if (oFocused === oItem)
{ {
bNext = true; bNext = true;
} }
@ -4232,7 +4302,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
{ {
for (; iIndex < iListLen; iIndex++) for (; iIndex < iListLen; iIndex++)
{ {
if (oSelected === aList[iIndex]) if (oFocused === aList[iIndex])
{ {
iIndex += iPageStep; iIndex += iPageStep;
iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex; iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex;
@ -4245,7 +4315,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
{ {
for (iIndex = iListLen; iIndex >= 0; iIndex--) for (iIndex = iListLen; iIndex >= 0; iIndex--)
{ {
if (oSelected === aList[iIndex]) if (oFocused === aList[iIndex])
{ {
iIndex -= iPageStep; iIndex -= iPageStep;
iIndex = 0 > iIndex ? 0 : iIndex; iIndex = 0 > iIndex ? 0 : iIndex;
@ -4259,53 +4329,43 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
if (oResult) if (oResult)
{ {
if (oSelected) if (oFocused)
{ {
if (bShiftKey) if (bShiftKey)
{ {
if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode) if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
else if (Enums.EventKeyCode.Insert === iEventKeyCode) else if (Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
this.throttleSelection = true; this.focusedItem(oResult);
this.selectedItem(oResult);
this.throttleSelection = true;
if (0 !== this.iSelectTimer) if (this.bAutoSelect && Enums.EventKeyCode.Space !== iEventKeyCode)
{ {
window.clearTimeout(this.iSelectTimer); window.clearTimeout(this.iSelectTimer);
this.iSelectTimer = window.setTimeout(function () { this.iSelectTimer = window.setTimeout(function () {
self.iSelectTimer = 0; self.iSelectTimer = 0;
self.actionClick(oResult); self.actionClick(oResult);
}, 1000); }, 300);
}
else
{
this.iSelectTimer = window.setTimeout(function () {
self.iSelectTimer = 0;
}, 200);
this.actionClick(oResult);
} }
this.scrollToSelected(); this.scrollToFocused();
} }
else if (oSelected) else if (oFocused)
{ {
if (bShiftKey && (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode)) if (bShiftKey && (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode))
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
else if (Enums.EventKeyCode.Insert === iEventKeyCode) else if (Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Space === iEventKeyCode)
{ {
oSelected.checked(!oSelected.checked()); oFocused.checked(!oFocused.checked());
} }
} }
}; };
@ -4313,7 +4373,7 @@ Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
/** /**
* @return {boolean} * @return {boolean}
*/ */
Selector.prototype.scrollToSelected = function () Selector.prototype.scrollToFocused = function ()
{ {
if (!this.oContentVisible || !this.oContentScrollable) if (!this.oContentVisible || !this.oContentScrollable)
{ {
@ -4322,13 +4382,13 @@ Selector.prototype.scrollToSelected = function ()
var var
iOffset = 20, iOffset = 20,
oSelected = $(this.sItemSelectedSelector, this.oContentScrollable), oFocused = $(this.sItemFocusedSelector, this.oContentScrollable),
oPos = oSelected.position(), oPos = oFocused.position(),
iVisibleHeight = this.oContentVisible.height(), iVisibleHeight = this.oContentVisible.height(),
iSelectedHeight = oSelected.outerHeight() iFocusedHeight = oFocused.outerHeight()
; ;
if (oPos && (oPos.top < 0 || oPos.top + iSelectedHeight > iVisibleHeight)) if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight))
{ {
if (oPos.top < 0) if (oPos.top < 0)
{ {
@ -4336,7 +4396,7 @@ Selector.prototype.scrollToSelected = function ()
} }
else else
{ {
this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iSelectedHeight + iOffset); this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iFocusedHeight + iOffset);
} }
return true; return true;
@ -4394,7 +4454,6 @@ Selector.prototype.eventClickFunction = function (oItem, oEvent)
}; };
/** /**
*
* @param {Object} oItem * @param {Object} oItem
* @param {Object=} oEvent * @param {Object=} oEvent
*/ */
@ -4418,6 +4477,7 @@ Selector.prototype.actionClick = function (oItem, oEvent)
} }
oItem.checked(!oItem.checked()); oItem.checked(!oItem.checked());
this.eventClickFunction(oItem, oEvent); this.eventClickFunction(oItem, oEvent);
} }
else if (oEvent.ctrlKey) else if (oEvent.ctrlKey)
@ -4432,7 +4492,6 @@ Selector.prototype.actionClick = function (oItem, oEvent)
if (bClick) if (bClick)
{ {
this.selectedItem(oItem); this.selectedItem(oItem);
this.sLastUid = sUid;
} }
} }
}; };
@ -9524,7 +9583,9 @@ function PopupsContactsViewModel()
this.contacts = ko.observableArray([]); this.contacts = ko.observableArray([]);
this.contacts.loading = ko.observable(false).extend({'throttle': 200}); this.contacts.loading = ko.observable(false).extend({'throttle': 200});
this.contacts.importing = ko.observable(false).extend({'throttle': 200}); this.contacts.importing = ko.observable(false).extend({'throttle': 200});
this.currentContact = ko.observable(null); this.currentContact = ko.observable(null);
this.currentFocusedContact = ko.observable(null);
this.importUploaderButton = ko.observable(null); this.importUploaderButton = ko.observable(null);
@ -9651,8 +9712,9 @@ function PopupsContactsViewModel()
}); });
}, this); }, this);
this.selector = new Selector(this.contacts, this.currentContact, this.selector = new Selector(this.contacts, this.currentFocusedContact, this.currentContact,
'.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem'); '.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem',
'.e-contact-item.focused');
this.selector.on('onItemSelect', _.bind(function (oContact) { this.selector.on('onItemSelect', _.bind(function (oContact) {
this.populateViewContact(oContact ? oContact : null); this.populateViewContact(oContact ? oContact : null);
@ -11685,6 +11747,7 @@ function MailBoxMessageListViewModel()
this.message = oData.message; this.message = oData.message;
this.messageList = oData.messageList; this.messageList = oData.messageList;
this.currentMessage = oData.currentMessage; this.currentMessage = oData.currentMessage;
this.currentFocusedMessage = oData.currentFocusedMessage;
this.isMessageSelected = oData.isMessageSelected; this.isMessageSelected = oData.isMessageSelected;
this.messageListSearch = oData.messageListSearch; this.messageListSearch = oData.messageListSearch;
this.messageListError = oData.messageListError; this.messageListError = oData.messageListError;
@ -11857,8 +11920,9 @@ function MailBoxMessageListViewModel()
this.quotaTooltip = _.bind(this.quotaTooltip, this); this.quotaTooltip = _.bind(this.quotaTooltip, this);
this.selector = new Selector(this.messageList, this.currentMessage, this.selector = new Selector(this.messageList, this.currentFocusedMessage, this.currentMessage,
'.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage'); '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage',
'.messageListItem.focused');
this.selector.on('onItemSelect', _.bind(function (oMessage) { this.selector.on('onItemSelect', _.bind(function (oMessage) {
if (oMessage) if (oMessage)
@ -11881,6 +11945,13 @@ function MailBoxMessageListViewModel()
return oMessage ? oMessage.generateUid() : ''; return oMessage ? oMessage.generateUid() : '';
}); });
// this.selector.autoSelect(false);
oData.layout.subscribe(function (mValue) {
this.selector.autoSelect(Enums.Layout.NoPreview !== mValue);
}, this);
oData.layout.valueHasMutated();
RL RL
.sub('mailbox.message-list.selector.go-down', function () { .sub('mailbox.message-list.selector.go-down', function () {
this.selector.goDown(); this.selector.goDown();
@ -12353,7 +12424,7 @@ MailBoxMessageListViewModel.prototype.initShortcuts = function ()
}); });
// change focused state // change focused state
key('tab, enter', Enums.KeyState.MessageList, function () { key('tab', Enums.KeyState.MessageList, function () {
if (oData.useKeyboardShortcuts()) if (oData.useKeyboardShortcuts())
{ {
if (self.message()) if (self.message())
@ -12873,12 +12944,11 @@ MailBoxMessageViewViewModel.prototype.escShortcuts = function ()
else else
{ {
this.message.focused(false); this.message.focused(false);
}
if (Enums.Layout.NoPreview === RL.data().layout()) if (Enums.Layout.NoPreview === RL.data().layout())
{ {
RL.historyBack(); RL.historyBack();
} }
}
return false; return false;
} }
@ -12981,7 +13051,6 @@ MailBoxMessageViewViewModel.prototype.initShortcuts = function ()
key('delete, shift+delete', Enums.KeyState.MessageView, function (event, handler) { key('delete, shift+delete', Enums.KeyState.MessageView, function (event, handler) {
if (oData.useKeyboardShortcuts() && event) if (oData.useKeyboardShortcuts() && event)
{ {
self.deleteCommand();
if (handler && 'shift+delete' === handler.shortcut) if (handler && 'shift+delete' === handler.shortcut)
{ {
self.deleteWithoutMoveCommand(); self.deleteWithoutMoveCommand();
@ -14855,6 +14924,7 @@ function WebMailDataStorage()
}, this); }, this);
this.currentMessage = ko.observable(null); this.currentMessage = ko.observable(null);
this.currentFocusedMessage = ko.observable(null);
this.message.subscribe(function (oMessage) { this.message.subscribe(function (oMessage) {
if (null === oMessage) if (null === oMessage)
@ -15336,11 +15406,15 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
iUnseenCount = 0, iUnseenCount = 0,
oData = RL.data(), oData = RL.data(),
oCache = RL.cache(), oCache = RL.cache(),
bMoveSelected = false,
bGetNext = false,
oNextMessage = null,
aMessageList = oData.messageList(),
oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw), oFromFolder = RL.cache().getFolderFromCacheList(sFromFolderFullNameRaw),
oToFolder = '' === sToFolderFullNameRaw ? null : oCache.getFolderFromCacheList(sToFolderFullNameRaw || ''), oToFolder = '' === sToFolderFullNameRaw ? null : oCache.getFolderFromCacheList(sToFolderFullNameRaw || ''),
sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(), sCurrentFolderFullNameRaw = oData.currentFolderFullNameRaw(),
oCurrentMessage = oData.message(), oCurrentMessage = oData.message(),
aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(oData.messageList(), function (oMessage) { aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function (oMessage) {
return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove); return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove);
}) : [] }) : []
; ;
@ -15350,6 +15424,11 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
{ {
iUnseenCount++; iUnseenCount++;
} }
if (oMessage.selected())
{
bMoveSelected = true;
}
}); });
if (oFromFolder && !bCopy) if (oFromFolder && !bCopy)
@ -15385,10 +15464,33 @@ WebMailDataStorage.prototype.removeMessagesFromList = function (
} }
else else
{ {
// select next message
if (bMoveSelected)
{
_.each(aMessageList, function (oMessage) {
if (!oNextMessage && oMessage)
{
if (bGetNext && !oMessage.checked() && !oMessage.deleted() && !oMessage.selected())
{
oNextMessage = oMessage;
}
else if (!bGetNext && oMessage.selected())
{
bGetNext = true;
}
}
});
if (oNextMessage)
{
this.currentMessage(oNextMessage);
}
}
oData.messageListIsNotCompleted(true); oData.messageListIsNotCompleted(true);
_.each(aMessages, function (oMessage) { _.each(aMessages, function (oMessage) {
if (oCurrentMessage && oCurrentMessage.requestHash === oMessage.requestHash) if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash)
{ {
oCurrentMessage = null; oCurrentMessage = null;
oData.message(null); oData.message(null);
@ -16646,7 +16748,7 @@ WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder,
'FromFolder': sFolder, 'FromFolder': sFolder,
'ToFolder': sToFolder, 'ToFolder': sToFolder,
'Uids': aUids.join(',') 'Uids': aUids.join(',')
}, null, '', ['MessageList', 'Message']); }, null, '', ['MessageList']);
}; };
/** /**
@ -16674,7 +16776,7 @@ WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder
this.defaultRequest(fCallback, 'MessageDelete', { this.defaultRequest(fCallback, 'MessageDelete', {
'Folder': sFolder, 'Folder': sFolder,
'Uids': aUids.join(',') 'Uids': aUids.join(',')
}, null, '', ['MessageList', 'Message']); }, null, '', ['MessageList']);
}; };
/** /**
@ -17942,10 +18044,13 @@ function RainLoopApp()
this.oData = null; this.oData = null;
this.oRemote = null; this.oRemote = null;
this.oCache = null; this.oCache = null;
this.oMoveCache = {};
this.quotaDebounce = _.debounce(this.quota, 1000 * 30); this.quotaDebounce = _.debounce(this.quota, 1000 * 30);
this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this); this.moveOrDeleteResponseHelper = _.bind(this.moveOrDeleteResponseHelper, this);
this.messagesMoveTrigger = _.debounce(this.messagesMoveTrigger, 500);
window.setInterval(function () { window.setInterval(function () {
RL.pub('interval.30s'); RL.pub('interval.30s');
}, 30000); }, 30000);
@ -18095,6 +18200,57 @@ RainLoopApp.prototype.recacheInboxMessageList = function ()
RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true); RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true);
}; };
RainLoopApp.prototype.reloadMessageListHelper = function (bEmptyList)
{
RL.reloadMessageList(bEmptyList);
};
RainLoopApp.prototype.messagesMoveTrigger = function ()
{
var self = this;
_.each(this.oMoveCache, function (oItem) {
RL.remote().messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid']);
});
this.oMoveCache = {};
};
RainLoopApp.prototype.messagesMoveHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForMove)
{
var sH = '$$' + sFromFolderFullNameRaw + '$$' + sToFolderFullNameRaw + '$$';
if (!this.oMoveCache[sH])
{
this.oMoveCache[sH] = {
'From': sFromFolderFullNameRaw,
'To': sToFolderFullNameRaw,
'Uid': []
};
}
this.oMoveCache[sH]['Uid'] = _.union(this.oMoveCache[sH]['Uid'], aUidForMove);
this.messagesMoveTrigger();
};
RainLoopApp.prototype.messagesCopyHelper = function (sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy)
{
RL.remote().messagesCopy(
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
sToFolderFullNameRaw,
aUidForCopy
);
};
RainLoopApp.prototype.messagesDeleteHelper = function (sFromFolderFullNameRaw, aUidForRemove)
{
RL.remote().messagesDelete(
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
};
RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData) RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
{ {
if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder()) if (Enums.StorageResultType.Success === sResult && RL.data().currentFolder())
@ -18114,7 +18270,7 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
} }
} }
RL.reloadMessageList(0 === RL.data().messageList().length); RL.reloadMessageListHelper(0 === RL.data().messageList().length);
RL.quotaDebounce(); RL.quotaDebounce();
} }
}; };
@ -18125,12 +18281,7 @@ RainLoopApp.prototype.moveOrDeleteResponseHelper = function (sResult, oData)
*/ */
RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove) RainLoopApp.prototype.deleteMessagesFromFolderWithoutCheck = function (sFromFolderFullNameRaw, aUidForRemove)
{ {
RL.remote().messagesDelete( this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); RL.data().removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
}; };
@ -18186,25 +18337,14 @@ RainLoopApp.prototype.deleteMessagesFromFolder = function (iDeleteType, sFromFol
{ {
kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () { kn.showScreenPopup(PopupsAskViewModel, [Utils.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () {
RL.remote().messagesDelete( self.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
self.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
aUidForRemove
);
oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove); oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
}]); }]);
} }
else if (oMoveFolder) else if (oMoveFolder)
{ {
RL.remote().messagesMove( this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove);
this.moveOrDeleteResponseHelper,
sFromFolderFullNameRaw,
oMoveFolder.fullNameRaw,
aUidForRemove
);
oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw); oData.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw);
} }
}; };
@ -18226,14 +18366,14 @@ RainLoopApp.prototype.moveMessagesToFolder = function (sFromFolderFullNameRaw, a
if (oFromFolder && oToFolder) if (oFromFolder && oToFolder)
{ {
bCopy = Utils.isUnd(bCopy) ? false : !!bCopy; if (Utils.isUnd(bCopy) ? false : !!bCopy)
{
RL.remote()[bCopy ? 'messagesCopy' : 'messagesMove']( this.messagesCopyHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
this.moveOrDeleteResponseHelper, }
oFromFolder.fullNameRaw, else
oToFolder.fullNameRaw, {
aUidForMove this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
); }
RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy); RL.data().removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy);
return true; return true;

File diff suppressed because one or more lines are too long