(js) Add "Move To" option for selected messages

Fixes #3477
This commit is contained in:
Francis Lachapelle
2016-02-03 16:48:04 -05:00
parent 0e2b1e41a7
commit f321e1c949
6 changed files with 173 additions and 94 deletions

1
NEWS
View File

@@ -3,6 +3,7 @@
Enhancements
- improved scrolling behavior when deleting a single message (#3489)
- added "Move To" option for selected messages (#3477)
Bug fixes
- fixed blank calendar view when selecting "Descending Order" in the sort menu

View File

@@ -478,7 +478,7 @@
response = [co moveUIDs: uids toFolder: destinationFolder inContext: context];
if (!response)
{
// Verify if the message beeing delete is saved as the root of a collapsed thread
// Verify if the message being deleted is saved as the root of a collapsed thread
us = [[context activeUser] userSettings];
moduleSettings = [us objectForKey: @"Mail"];
threadsCollapsed = [moduleSettings objectForKey: @"threadsCollapsed"];
@@ -501,7 +501,7 @@
else
{
data = [NSDictionary dictionaryWithObject: [self labelForKey: @"Error moving messages." inContext: context]
forKey: @"error"];
forKey: @"message"];
response = [self responseWithStatus: 500 andJSONRepresentation: data];
}

View File

@@ -155,28 +155,6 @@
<md-button class="sg-icon-button" ng-click="mailbox.confirmDeleteSelectedMessages()">
<md-icon>delete</md-icon>
</md-button>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Copy messages" ng-click="$mdOpenMenu()">
<md-tooltip md-direction="bottom"><var:string label:value="Copy To"/></md-tooltip>
<md-icon>content_copy</md-icon>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true">{{account.name}}</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in
account.$flattenMailboxes({ all: true })
track by folder.path"
ng-hide="mailbox.id == folder.id">
<md-button ng-click="mailbox.copySelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</div>
</md-menu-content>
</md-menu>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="More messages options" ng-click="$mdOpenMenu()">
<md-icon>more_vert</md-icon>
@@ -197,6 +175,52 @@
<var:string label:value="Save As..."/>
</md-button>
</md-menu-item>
<md-menu-item>
<md-menu>
<md-button label:aria-label="Copy To" ng-click="$mdOpenMenu($event)">
<var:string label:value="Copy To"/>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true">{{account.name}}</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in
account.$flattenMailboxes({ all: true })
track by folder.path"
ng-hide="mailbox.id == folder.id">
<md-button ng-click="mailbox.copySelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</div>
</md-menu-content>
</md-menu>
</md-menu-item>
<md-menu-item>
<md-menu>
<md-button label:aria-label="Move To" ng-click="$mdOpenMenu($event)">
<var:string label:value="Move To"/>
</md-button>
<md-menu-content width="4">
<div ng-repeat="account in mailbox.accounts track by account.id">
<md-menu-item>
<md-button class="md-primary" ng-disabled="true">{{account.name}}</md-button>
</md-menu-item>
<md-menu-divider><!-- divider --></md-menu-divider>
<md-menu-item ng-repeat="folder in
account.$flattenMailboxes({ all: true })
track by folder.path"
ng-hide="mailbox.id == folder.id">
<md-button ng-click="mailbox.moveSelectedMessages(folder.id)">
<span ng-class="'sg-child-level-' + folder.level">{{folder.name}}</span>
</md-button>
</md-menu-item>
</div>
</md-menu-content>
</md-menu>
</md-menu-item>
</md-menu-content>
</md-menu>
</div>

View File

@@ -517,6 +517,44 @@
});
};
/**
* @function $_deleteMessages
* @memberof Mailbox.prototype
* @desc Delete multiple messages from Mailbox object.
* @param {string[]} uids - the messages uids
* @param {object[]} messages - the Message instances
* @return the index of the first deleted message
*/
Mailbox.prototype.$_deleteMessages = function(uids, messages) {
var _this = this, selectedMessages, selectedUIDs, unseen, firstIndex = this.$messages.length;
// Decrement the unseen count
unseen = _.filter(messages, function(message, i) { return !message.isread; });
this.unseenCount -= unseen.length;
// Remove messages from $messages and uidsMap
_.forEachRight(this.$messages, function(message, index) {
var selectedIndex = _.findIndex(uids, function(uid) {
return message.uid == uid;
});
if (selectedIndex > -1) {
uids.splice(selectedIndex, 1);
delete _this.uidsMap[message.uid];
if (message.uid == _this.selectedMessage)
delete _this.selectedMessage;
_this.$messages.splice(index, 1);
if (index < firstIndex)
firstIndex = index;
}
else {
_this.uidsMap[message.uid] -= uids.length;
}
});
// Return the index of the first deleted message
return firstIndex;
};
/**
* @function $deleteMessages
* @memberof Mailbox.prototype
@@ -529,33 +567,11 @@
uids = _.pluck(messages, 'uid');
return Mailbox.$$resource.post(this.id, 'batchDelete', {uids: uids})
.then(function(data) {
var selectedMessages, selectedUIDs, unseen, firstIndex = _this.$messages.length;
// Decrement the unseenCount accordingly
unseen = _.filter(messages, function(message, i) { return !message.isread; });
_this.unseenCount -= unseen.length;
// Remove messages from $messages and uidsMap
_.forEachRight(_this.$messages, function(message, index) {
var selectedIndex = _.findIndex(uids, function(uid) {
return message.uid == uid;
});
if (selectedIndex > -1) {
uids.splice(selectedIndex, 1);
delete _this.uidsMap[message.uid];
if (message.uid == _this.selectedMessage)
delete _this.selectedMessage;
_this.$messages.splice(index, 1);
if (index < firstIndex)
firstIndex = index;
}
else {
_this.uidsMap[message.uid] -= uids.length;
}
});
// Update inbox quota
if (data.quotas)
_this.$account.updateQuota(data.quotas);
return firstIndex;
return _this.$_deleteMessages(uids, messages);
});
};
@@ -566,6 +582,8 @@
* @return a promise of the HTTP operation
*/
Mailbox.prototype.$copyMessages = function(uids, folder) {
var _this = this;
return Mailbox.$$resource.post(this.id, 'copyMessages', {uids: uids, folder: folder})
.then(function(data) {
// Update inbox quota
@@ -580,8 +598,14 @@
* @desc Move multiple messages from the current mailbox to a target one
* @return a promise of the HTTP operation
*/
Mailbox.prototype.$moveMessages = function(uids, folder) {
return Mailbox.$$resource.post(this.id, 'moveMessages', {uids: uids, folder: folder});
Mailbox.prototype.$moveMessages = function(messages, folder) {
var _this = this, uids;
uids = _.pluck(messages, 'uid');
return Mailbox.$$resource.post(this.id, 'moveMessages', {uids: uids, folder: folder})
.then(function() {
return _this.$_deleteMessages(uids, messages);
});
};
/**

View File

@@ -24,7 +24,7 @@
vm.unselectMessages = unselectMessages;
vm.confirmDeleteSelectedMessages = confirmDeleteSelectedMessages;
vm.copySelectedMessages = copySelectedMessages;
// vm.moveSelectedMessages = moveSelectedMessages;
vm.moveSelectedMessages = moveSelectedMessages;
vm.saveSelectedMessages = saveSelectedMessages;
vm.markSelectedMessagesAsFlagged = markSelectedMessagesAsFlagged;
vm.markSelectedMessagesAsUnread = markSelectedMessagesAsUnread;
@@ -56,65 +56,73 @@
Dialog.confirm(l('Warning'),
l('Are you sure you want to delete the selected messages?'))
.then(function() {
// User confirmed the deletion
var unselectMessage = false;
var deleteSelectedMessage = false;
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) {
if (message.selected &&
message.uid == vm.selectedFolder.selectedMessage)
unselectMessage = true;
deleteSelectedMessage = true;
return message.selected;
});
vm.selectedFolder.$deleteMessages(selectedMessages).then(function(index) {
var nextMessage, previousMessage, nextIndex = index;
if (unselectMessage) {
if (Mailbox.$virtualMode) {
$state.go('mail.account.virtualMailbox');
}
else {
// Select either the next or previous message
if (index > 0) {
nextIndex -= 1;
nextMessage = vm.selectedFolder.$messages[nextIndex];
}
if (index < vm.selectedFolder.$messages.length)
previousMessage = vm.selectedFolder.$messages[index];
if (nextMessage) {
if (nextMessage.isread && previousMessage && !previousMessage.isread) {
nextIndex = index;
nextMessage = previousMessage;
}
}
else if (previousMessage) {
nextIndex = index;
nextMessage = previousMessage;
}
if (nextMessage) {
$state.go('mail.account.mailbox.message', { messageId: nextMessage.uid });
vm.selectedFolder.$topIndex = nextIndex;
}
else {
$state.go('mail.account.mailbox');
}
}
}
unselectMessage(deleteSelectedMessage, index);
});
});
}
function unselectMessage(message, index) {
// Unselect current message and cleverly load the next message
var nextMessage, previousMessage, nextIndex = index;
if (message) {
if (Mailbox.$virtualMode) {
$state.go('mail.account.virtualMailbox');
}
else {
// Select either the next or previous message
if (index > 0) {
nextIndex -= 1;
nextMessage = vm.selectedFolder.$messages[nextIndex];
}
if (index < vm.selectedFolder.$messages.length)
previousMessage = vm.selectedFolder.$messages[index];
if (nextMessage) {
if (nextMessage.isread && previousMessage && !previousMessage.isread) {
nextIndex = index;
nextMessage = previousMessage;
}
}
else if (previousMessage) {
nextIndex = index;
nextMessage = previousMessage;
}
if (nextMessage) {
$state.go('mail.account.mailbox.message', { messageId: nextMessage.uid });
vm.selectedFolder.$topIndex = nextIndex;
}
else {
$state.go('mail.account.mailbox');
}
}
}
}
function copySelectedMessages(folder) {
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) { return message.selected; });
var selectedUIDs = _.pluck(selectedMessages, 'uid');
vm.selectedFolder.$copyMessages(selectedUIDs, '/' + folder);
}
// function moveSelectedMessages(folder) {
// var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) { return message.selected });
// var selectedUIDs = _.pluck(selectedMessages, 'uid');
// vm.selectedFolder.$moveMessages(selectedUIDs, '/' + folder).then(function() {
// // TODO: refresh target mailbox?
// vm.selectedFolder.$messages = _.difference(vm.selectedFolder.$messages, selectedMessages);
// });
// }
function moveSelectedMessages(folder) {
var moveSelectedMessage = false;
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) {
if (message.selected &&
message.uid == vm.selectedFolder.selectedMessage)
moveSelectedMessage = true;
return message.selected;
});
vm.selectedFolder.$moveMessages(selectedMessages, '/' + folder).then(function(index) {
unselectMessage(moveSelectedMessage, index);
});
}
function saveSelectedMessages() {
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) { return message.selected; });

View File

@@ -20,4 +20,26 @@ md-sidenav {
}
}
}
}
}
// submenu hack
// See https://github.com/angular/material/issues/6096
md-menu-content {
.md-menu {
@extend md-menu-item;
padding: 0;
> .md-button {
line-height: $menu-item-height;
&:after {
display: block;
content: '\25BC';
position: absolute;
top: 0px;
speak: none;
transform: rotate(270deg) scaleY(0.45) scaleX(0.9);
right: 2 * $baseline-grid;
}
}
}
}