(js) Add batch operations in advanced search

pull/217/head
Francis Lachapelle 2016-06-23 16:03:14 -04:00
parent cf3a9b89b6
commit 13e826b6f2
5 changed files with 228 additions and 177 deletions

1
NEWS
View File

@ -7,6 +7,7 @@ New features
Enhancements
- [eas] use the preferred email identity in EAS if valid (#3698)
- [eas] handle inline attachments during EAS content generation
- [web] all batch operations can now be performed on selected messages in advanced search mode
Bug fixes
- [web] fixed crash when an attachment filename has no extension

View File

@ -65,11 +65,11 @@
<!-- sort mode (default) -->
<div class="md-toolbar-tools" ng-hide="mailbox.mode.search">
<md-button class="sg-icon-button" label:aria-label="Search"
ng-click="mailbox.mode.search = true">
ng-click="mailbox.searchMode()">
<md-icon>search</md-icon>
</md-button>
<a href="javascript:void(0)" class="sg-folder-name"
ng-click="mailbox.mode.search = true">{{mailbox.selectedFolder.name}}</a>
ng-click="mailbox.searchMode()">{{mailbox.selectedFolder.name}}</a>
<md-menu>
<md-button class="sg-icon-button" label:aria-label="Sort"
ng-click="$mdOpenMenu()">
@ -128,7 +128,7 @@
<md-icon>arrow_back</md-icon>
</md-button>
<md-input-container class="md-flex" md-no-float="md-no-float">
<input name="folderSearch" type="search" var:minlength="minimumSearchLength" label:placeholder="Search"/>
<input name="folderSearch" type="search" var:minlength="minimumSearchLength" label:placeholder="Search" sg-focus-on="search" />
<div ng-messages="searchForm.folderSearch.$error" ng-show="searchForm.folderSearch.$dirty">
<div ng-message="minlength"><var:string value="minimumSearchLengthLabel"/></div>
</div>

View File

@ -221,6 +221,16 @@
return Mailbox.$absolutePath(this.$account.id, this.path);
};
/**
* @function $selectedMessages
* @memberof Mailbox.prototype
* @desc Return the messages selected by the user.
* @returns Message instances
*/
Mailbox.prototype.$selectedMessages = function() {
return _.filter(this.$messages, function(message) { return message.selected; });
};
/**
* @function $selectedCount
* @memberof Mailbox.prototype
@ -228,13 +238,7 @@
* @returns the number of selected messages
*/
Mailbox.prototype.$selectedCount = function() {
var count;
count = 0;
if (this.$messages) {
count = (_.filter(this.$messages, function(message) { return message.selected; })).length;
}
return count;
return this.$selectedMessages().length;
};
/**
@ -542,12 +546,14 @@
* @desc Add or remove a flag on a message set
* @returns a promise of the HTTP operation
*/
Mailbox.prototype.$flagMessages = function(uids, flags, operation) {
var data = {msgUIDs: uids,
Mailbox.prototype.$flagMessages = function(messages, flags, operation) {
var data = {msgUIDs: _.map(messages, 'uid'),
flags: flags,
operation: operation};
return Mailbox.$$resource.post(this.id, 'addOrRemoveLabel', data);
return Mailbox.$$resource.post(this.id, 'addOrRemoveLabel', data).then(function() {
return messages;
});
};
/**
@ -656,9 +662,9 @@
* @return a promise of the HTTP operation
*/
Mailbox.prototype.$markOrUnMarkMessagesAsJunk = function(messages) {
var _this = this, uids;
var method = (this.type == 'junk' ? 'markMessagesAsNotJunk' : 'markMessagesAsJunk');
uids = _.map(messages, 'uid');
var _this = this,
uids = _.map(messages, 'uid'),
method = (this.type == 'junk' ? 'markMessagesAsNotJunk' : 'markMessagesAsJunk');
return Mailbox.$$resource.post(this.id, method, {uids: uids});
};
@ -669,8 +675,9 @@
* @desc Copy multiple messages from the current mailbox to a target one
* @return a promise of the HTTP operation
*/
Mailbox.prototype.$copyMessages = function(uids, folder) {
var _this = this;
Mailbox.prototype.$copyMessages = function(messages, folder) {
var _this = this,
uids = _.map(messages, 'uid');
return Mailbox.$$resource.post(this.id, 'copyMessages', {uids: uids, folder: folder})
.then(function(data) {

View File

@ -6,8 +6,8 @@
/**
* @ngInject
*/
MailboxController.$inject = ['$window', '$timeout', '$state', '$mdDialog', 'stateAccounts', 'stateAccount', 'stateMailbox', 'encodeUriFilter', 'Dialog', 'Account', 'Mailbox'];
function MailboxController($window, $timeout, $state, $mdDialog, stateAccounts, stateAccount, stateMailbox, encodeUriFilter, Dialog, Account, Mailbox) {
MailboxController.$inject = ['$window', '$timeout', '$q', '$state', '$mdDialog', 'stateAccounts', 'stateAccount', 'stateMailbox', 'encodeUriFilter', 'sgFocus', 'Dialog', 'Account', 'Mailbox'];
function MailboxController($window, $timeout, $q, $state, $mdDialog, stateAccounts, stateAccount, stateMailbox, encodeUriFilter, focus, Dialog, Account, Mailbox) {
var vm = this, messageDialog = null;
// Expose controller
@ -21,7 +21,12 @@
vm.selectedFolder = stateMailbox;
vm.selectMessage = selectMessage;
vm.toggleMessageSelection = toggleMessageSelection;
vm.unselectMessages = unselectMessages;
vm.sort = sort;
vm.sortedBy = sortedBy;
vm.searchMode = searchMode;
vm.cancelSearch = cancelSearch;
vm.newMessage = newMessage;
vm.mode = { search: false, multiple: 0 };
vm.confirmDeleteSelectedMessages = confirmDeleteSelectedMessages;
vm.markOrUnMarkMessagesAsJunk = markOrUnMarkMessagesAsJunk;
vm.copySelectedMessages = copySelectedMessages;
@ -29,160 +34,7 @@
vm.markSelectedMessagesAsFlagged = markSelectedMessagesAsFlagged;
vm.markSelectedMessagesAsUnread = markSelectedMessagesAsUnread;
vm.selectAll = selectAll;
vm.sort = sort;
vm.sortedBy = sortedBy;
vm.cancelSearch = cancelSearch;
vm.newMessage = newMessage;
vm.mode = { search: false, multiple: 0 };
function selectMessage(message) {
if (Mailbox.$virtualMode)
$state.go('mail.account.virtualMailbox.message', {accountId: stateAccount.id, mailboxId: encodeUriFilter(message.$mailbox.path), messageId: message.uid});
else
$state.go('mail.account.mailbox.message', {messageId: message.uid});
}
function toggleMessageSelection($event, message) {
message.selected = !message.selected;
vm.mode.multiple += message.selected? 1 : -1;
$event.preventDefault();
$event.stopPropagation();
}
function unselectMessages() {
_.forEach(vm.selectedFolder.$messages, function(message) {
message.selected = false;
});
vm.mode.multiple = 0;
}
function confirmDeleteSelectedMessages() {
Dialog.confirm(l('Warning'),
l('Are you sure you want to delete the selected messages?'),
{ ok: l('Delete') })
.then(function() {
var deleteSelectedMessage = false;
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) {
if (message.selected &&
message.uid == vm.selectedFolder.selectedMessage)
deleteSelectedMessage = true;
return message.selected;
});
vm.selectedFolder.$deleteMessages(selectedMessages).then(function(index) {
unselectMessage(deleteSelectedMessage, index);
});
});
}
function markOrUnMarkMessagesAsJunk() {
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.$markOrUnMarkMessagesAsJunk(selectedMessages).then(function() {
var folder = '/' + vm.account.id + '/folderINBOX';
if (vm.selectedFolder.type != 'junk') {
folder = '/' + vm.account.$getMailboxByType('junk').id;
}
vm.selectedFolder.$moveMessages(selectedMessages, folder).then(function(index) {
unselectMessage(moveSelectedMessage, index);
});
});
}
function unselectMessage(message, index) {
// Unselect current message and cleverly load the next message
var nextMessage, previousMessage, nextIndex = index;
vm.mode.multiple = vm.selectedFolder.$selectedCount();
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 = _.map(selectedMessages, 'uid');
vm.selectedFolder.$copyMessages(selectedUIDs, '/' + folder);
}
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 selectAll() {
var i = 0, length = vm.selectedFolder.$messages.length;
for (; i < length; i++)
vm.selectedFolder.$messages[i].selected = true;
vm.mode.multiple = length;
}
function markSelectedMessagesAsFlagged() {
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) { return message.selected; });
var selectedUIDs = _.map(selectedMessages, 'uid');
vm.selectedFolder.$flagMessages(selectedUIDs, '\\Flagged', 'add').then(function(d) {
// Success
_.forEach(selectedMessages, function(message) {
message.isflagged = true;
});
});
}
function markSelectedMessagesAsUnread() {
var selectedMessages = _.filter(vm.selectedFolder.$messages, function(message) { return message.selected; });
var selectedUIDs = _.map(selectedMessages, 'uid');
vm.selectedFolder.$flagMessages(selectedUIDs, 'seen', 'remove').then(function(d) {
// Success
_.forEach(selectedMessages, function(message) {
message.isread = false;
vm.selectedFolder.unseenCount++;
});
});
}
vm.unselectMessages = unselectMessages;
function sort(field) {
vm.selectedFolder.$filter({ sort: field });
@ -192,6 +44,11 @@
return Mailbox.$query.sort == field;
}
function searchMode() {
vm.mode.search = true;
focus('search');
}
function cancelSearch() {
vm.mode.search = false;
vm.selectedFolder.$filter().then(function() {
@ -228,6 +85,183 @@
});
}
}
function selectMessage(message) {
if (Mailbox.$virtualMode)
$state.go('mail.account.virtualMailbox.message', {mailboxId: encodeUriFilter(message.$mailbox.path), messageId: message.uid});
else
$state.go('mail.account.mailbox.message', {messageId: message.uid});
}
function toggleMessageSelection($event, message) {
message.selected = !message.selected;
vm.mode.multiple += message.selected? 1 : -1;
$event.preventDefault();
$event.stopPropagation();
}
/**
* Batch operations
*/
function _currentMailboxes() {
if (Mailbox.$virtualMode)
return vm.selectedFolder.$mailboxes;
else
return [vm.selectedFolder];
}
function _unselectMessage(message, index) {
// Unselect current message and cleverly load the next message.
// This function must not be called in virtual mode.
var nextMessage, previousMessage, nextIndex = index;
vm.mode.multiple = vm.selectedFolder.$selectedCount();
if (message) {
// 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) {
vm.selectedFolder.$topIndex = nextIndex;
$state.go('mail.account.mailbox.message', { messageId: nextMessage.uid });
}
else {
$state.go('mail.account.mailbox');
}
}
else {
$timeout(function() {
console.warn('go to mailbox');
$state.go('mail.account.mailbox');
});
}
}
function confirmDeleteSelectedMessages() {
Dialog.confirm(l('Warning'),
l('Are you sure you want to delete the selected messages?'),
{ ok: l('Delete') })
.then(function() {
var deleteSelectedMessage = vm.selectedFolder.hasSelectedMessage();
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$deleteMessages(selectedMessages).then(function(index) {
if (Mailbox.$virtualMode) {
// When performing an advanced search, we refresh the view if the selected message
// was deleted, but only once all promises have completed.
if (deleteSelectedMessage)
$state.go('mail.account.virtualMailbox');
}
else {
// In normal mode, we immediately unselect the selected message.
_unselectMessage(deleteSelectedMessage, index);
}
});
});
}
function markOrUnMarkMessagesAsJunk() {
var moveSelectedMessage = vm.selectedFolder.hasSelectedMessage();
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$markOrUnMarkMessagesAsJunk(selectedMessages).then(function() {
var dstFolder = '/' + vm.account.id + '/folderINBOX';
if (vm.selectedFolder.type != 'junk') {
dstFolder = '/' + vm.account.$getMailboxByType('junk').id;
}
vm.selectedFolder.$moveMessages(selectedMessages, dstFolder).then(function(index) {
if (Mailbox.$virtualMode) {
// When performing an advanced search, we refresh the view if the selected message
// was deleted, but only once all promises have completed.
if (moveSelectedMessage)
$state.go('mail.account.virtualMailbox');
}
else {
// In normal mode, we immediately unselect the selected message.
_unselectMessage(moveSelectedMessage, index);
}
});
});
}
function copySelectedMessages(dstFolder) {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$copyMessages(selectedMessages, '/' + dstFolder);
}
function moveSelectedMessages(dstFolder) {
var moveSelectedMessage = vm.selectedFolder.hasSelectedMessage();
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$moveMessages(selectedMessages, '/' + dstFolder).then(function(index) {
if (Mailbox.$virtualMode) {
// When performing an advanced search, we refresh the view if the selected message
// was moved, but only once all promises have completed.
if (moveSelectedMessage)
$state.go('mail.account.virtualMailbox');
}
else {
// In normal mode, we immediately unselect the selected message.
_unselectMessage(moveSelectedMessage, index);
}
});
}
function selectAll() {
var count = 0;
_.forEach(_currentMailboxes(), function(folder) {
var i = 0, length = folder.$messages.length;
for (; i < length; i++)
folder.$messages[i].selected = true;
count += length;
});
vm.mode.multiple = count;
}
function unselectMessages() {
_.forEach(_currentMailboxes(), function(folder) {
_.forEach(folder.$messages, function(message) {
message.selected = false;
});
});
vm.mode.multiple = 0;
}
function markSelectedMessagesAsFlagged() {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$flagMessages(selectedMessages, '\\Flagged', 'add').then(function(messages) {
_.forEach(messages, function(message) {
message.isflagged = true;
});
});
}
function markSelectedMessagesAsUnread() {
var selectedMessages = vm.selectedFolder.$selectedMessages();
if (_.size(selectedMessages) > 0)
vm.selectedFolder.$flagMessages(selectedMessages, 'seen', 'remove').then(function(messages) {
_.forEach(messages, function(message) {
message.isread = false;
message.$mailbox.unseenCount++;
});
});
}
}
angular

View File

@ -521,10 +521,19 @@
* @returns a promise of the HTTP operation
*/
Message.prototype.$reload = function(options) {
var futureMessageData;
var _this = this, futureMessageData;
if (options && options.useCache && this.$futureMessageData)
if (options && options.useCache && this.$futureMessageData) {
if (!this.isread) {
Message.$$resource.fetch(this.$absolutePath(), 'markMessageRead').then(function() {
Message.$timeout(function() {
_this.isread = true;
_this.$mailbox.unseenCount--;
});
});
}
return this;
}
futureMessageData = Message.$$resource.fetch(this.$absolutePath(options), 'view');