(feat) initial implementation of advanced email search

There's one bug where viewing of the messages from the results
is still impossible due to the ui-router. This will be fixed
very soon.
This commit is contained in:
Ludovic Marcotte
2015-09-10 16:38:30 -04:00
parent b646e35f5d
commit cb0d327f90
7 changed files with 490 additions and 26 deletions
@@ -43,6 +43,7 @@
$query: { sort: 'date', asc: 0 },
selectedFolder: null,
$refreshTimeout: null,
$virtualMode: false,
PRELOAD: PRELOAD
});
// Initialize sort parameters from user's settings
@@ -272,10 +273,12 @@
}
// Restart the refresh timer, if needed
var refreshViewCheck = Mailbox.$Preferences.defaults.SOGoRefreshViewCheck;
if (refreshViewCheck && refreshViewCheck != 'manually') {
var f = angular.bind(_this, Mailbox.prototype.$filter);
Mailbox.$refreshTimeout = Mailbox.$timeout(f, refreshViewCheck.timeInterval()*1000);
if (!Mailbox.$virtualMode) {
var refreshViewCheck = Mailbox.$Preferences.defaults.SOGoRefreshViewCheck;
if (refreshViewCheck && refreshViewCheck != 'manually') {
var f = angular.bind(_this, Mailbox.prototype.$filter);
Mailbox.$refreshTimeout = Mailbox.$timeout(f, refreshViewCheck.timeInterval()*1000);
}
}
var futureMailboxData = Mailbox.$$resource.post(_this.id, 'view', options);
@@ -10,7 +10,8 @@
function MailboxController($state, $timeout, $mdDialog, stateAccounts, stateAccount, stateMailbox, encodeUriFilter, focus, Dialog, Account, Mailbox) {
var vm = this, messageDialog = null;
Mailbox.selectedFolder = stateMailbox;
if (!Mailbox.$virtualMode)
Mailbox.selectedFolder = stateMailbox;
vm.service = Mailbox;
vm.accounts = stateAccounts;
@@ -33,7 +34,10 @@
vm.mode = { search: false };
function selectMessage(message) {
$state.go('mail.account.mailbox.message', {accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path), messageId: message.uid});
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', {accountId: stateAccount.id, mailboxId: encodeUriFilter(message.$mailbox.path), messageId: message.uid});
}
function toggleMessageSelection($event, message) {
@@ -6,8 +6,8 @@
/**
* @ngInject
*/
MailboxesController.$inject = ['$state', '$timeout', '$mdDialog', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Account', 'Mailbox', 'User', 'Preferences', 'stateAccounts'];
function MailboxesController($state, $timeout, $mdDialog, focus, encodeUriFilter, Dialog, Settings, Account, Mailbox, User, Preferences, stateAccounts) {
MailboxesController.$inject = ['$state', '$timeout', '$mdDialog', 'sgFocus', 'encodeUriFilter', 'Dialog', 'sgSettings', 'Account', 'Mailbox', 'VirtualMailbox', 'User', 'Preferences', 'stateAccounts'];
function MailboxesController($state, $timeout, $mdDialog, focus, encodeUriFilter, Dialog, Settings, Account, Mailbox, VirtualMailbox, User, Preferences, stateAccounts) {
var vm = this,
account,
mailbox;
@@ -30,6 +30,93 @@
vm.setFolderAs = setFolderAs;
vm.refreshUnseenCount = refreshUnseenCount;
// Advanced search options
vm.showingAdvancedSearch = false;
vm.currentSearchParam = '';
vm.addSearchParam = addSearchParam;
vm.newSearchParam = newSearchParam;
vm.showAdvancedSearch = showAdvancedSearch;
vm.hideAdvancedSearch = hideAdvancedSearch;
vm.startAdvancedSearch = startAdvancedSearch;
vm.stopAdvancedSearch = stopAdvancedSearch;
vm.search = {
options: {'': l('Select a criteria'),
subject: l('Enter Subject'),
from: l('Enter From'),
to: l('Enter To'),
cc: l('Enter Cc'),
body: l('Enter Body')
},
mailbox: 'INBOX',
subfolders: 1,
match: 'AND',
params: []
};
function showAdvancedSearch(path) {
vm.showingAdvancedSearch = true;
vm.search.mailbox = path;
}
function hideAdvancedSearch() {
vm.showingAdvancedSearch = false;
vm.service.$virtualMode = false;
account = vm.accounts[0];
mailbox = vm.searchPreviousMailbox;
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(mailbox.path) });
}
function startAdvancedSearch() {
var root, mailboxes = [];
vm.virtualMailbox = new VirtualMailbox(vm.accounts[0]);
// Don't set the previous selected mailbox if we're in virtual mode
// That allows users to do multiple advanced search but return
// correctly to the previously selected mailbox once done.
if (!Mailbox.$virtualMode)
vm.searchPreviousMailbox = Mailbox.selectedFolder;
Mailbox.selectedFolder = vm.virtualMailbox;
Mailbox.$virtualMode = true;
if (angular.isDefined(vm.search.mailbox)) {
root = vm.accounts[0].$getMailboxByPath(vm.search.mailbox);
mailboxes.push(root);
if (vm.search.subfolders && root.children.length)
mailboxes.push(root.children);
}
else {
mailboxes = vm.accounts[0].$flattenMailboxes();
}
vm.virtualMailbox.setMailboxes(mailboxes);
vm.virtualMailbox.startSearch(vm.search.match, vm.search.params);
$state.go('mail.account.virtualMailbox', { accountId: vm.accounts[0].id });
}
function stopAdvancedSearch() {
vm.virtualMailbox.stopSearch();
}
function addSearchParam(v) {
vm.currentSearchParam = v;
}
function newSearchParam(v) {
if (v.length && vm.currentSearchParam.length) {
var n = 0;
if (v.startsWith("!")) {
n = 1;
v = v.substring(1).trim();
}
vm.search.params.push({searchBy:vm.currentSearchParam, searchInput: v, negative: n});
vm.currentSearchParam = '';
}
}
if ($state.current.name == 'mail' && vm.accounts.length > 0 && vm.accounts[0].$mailboxes.length > 0) {
// Redirect to first mailbox of first account if no mailbox is selected
account = vm.accounts[0];
@@ -121,6 +208,8 @@
if (vm.editMode == folder.path)
return;
vm.editMode = false;
vm.showingAdvancedSearch = false;
vm.service.$virtualMode = false;
$state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) });
}
+52 -7
View File
@@ -39,6 +39,33 @@
stateAccount: stateAccount
}
})
.state('mail.account.virtualMailbox', {
url: '/virtual',
views: {
'mailbox@mail': {
templateUrl: 'UIxMailFolderTemplate', // UI/Templates/MailerUI/UIxMailFolderTemplate.wox
controller: 'MailboxController',
controllerAs: 'mailbox'
}
},
resolve: {
stateMailbox: function(Mailbox) { return Mailbox.selectedFolder; }
}
})
.state('mail.account.virtualMailbox.message', {
url: '/:mailboxId/:messageId',
views: {
message: {
templateUrl: 'UIxMailViewTemplate', // UI/Templates/MailerUI/UIxMailViewTemplate.wox
controller: 'MessageController',
controllerAs: 'viewer'
}
},
resolve: {
stateMailbox: stateVirtualMailbox,
stateMessage: stateMessage
}
})
.state('mail.account.mailbox', {
url: '/:mailboxId',
views: {
@@ -144,8 +171,8 @@
/**
* @ngInject
*/
stateMailbox.$inject = ['$stateParams', 'stateAccount', 'decodeUriFilter'];
function stateMailbox($stateParams, stateAccount, decodeUriFilter) {
stateMailbox.$inject = ['Mailbox', '$stateParams', 'stateAccount', 'decodeUriFilter'];
function stateMailbox(Mailbox, $stateParams, stateAccount, decodeUriFilter) {
var mailboxId = decodeUriFilter($stateParams.mailboxId),
_find;
// Recursive find function
@@ -162,14 +189,22 @@
}
return mailbox;
};
if (Mailbox.$virtualMode)
return Mailbox.selectedFolder;
//return $q.when(Mailbox.selectedFolder);
return _find(stateAccount.$mailboxes);
}
/**
* @ngInject
*/
stateMessages.$inject = ['stateMailbox'];
function stateMessages(stateMailbox) {
stateMessages.$inject = ['$q', 'Mailbox', 'stateMailbox'];
function stateMessages($q, Mailbox, stateMailbox) {
if (Mailbox.$virtualMode)
return [];
return stateMailbox.$filter();
}
@@ -181,12 +216,22 @@
// return stateAccount.$newMessage();
// }
stateVirtualMailbox.$inject = ['Mailbox', '$stateParams'];
function stateVirtualMailbox(Mailbox, $stateParams) {
return _.find(Mailbox.selectedFolder.$mailboxes, function(mailboxObject) {
return mailboxObject.path == $stateParams.mailboxId;
});
}
/**
* @ngInject
*/
stateMessage.$inject = ['encodeUriFilter', '$stateParams', '$state', 'stateMailbox', 'stateMessages'];
function stateMessage(encodeUriFilter, $stateParams, $state, stateMailbox, stateMessages) {
var message = _.find(stateMailbox.$messages, function(messageObject) {
stateMessage.$inject = ['Mailbox', 'encodeUriFilter', '$stateParams', '$state', 'stateMailbox', 'stateMessages'];
function stateMessage(Mailbox, encodeUriFilter, $stateParams, $state, stateMailbox, stateMessages) {
var message;
message = _.find(stateMailbox.$messages, function(messageObject) {
return messageObject.uid == $stateParams.messageId;
});
@@ -0,0 +1,219 @@
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
(function() {
'use strict';
/**
* @name VirtualMailbox
* @constructor
* @param {object} account - the mail account associated with the virtual search
*/
function VirtualMailbox(account) {
this.$account = account;
}
/**
* @memberof VirtualMailbox
* @desc The factory we'll use to register with Angular
* @returns the VirtualMailbox constructor
*/
VirtualMailbox.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'Message', 'Mailbox', 'sgMailbox_PRELOAD', function($q, $timeout, $log, Settings, Mailbox, Message, PRELOAD) {
angular.extend(VirtualMailbox, {
$q: $q,
$timeout: $timeout,
$log: $log,
$Message: Message,
selectedFolder: null,
PRELOAD: PRELOAD
});
return VirtualMailbox; // return constructor
}];
/**
* @module SOGo.MailerUI
* @desc Factory registration of VirtualMailbox in Angular module.
*/
try {
angular.module('SOGo.MailerUI');
}
catch(e) {
angular.module('SOGo.MailerUI', ['SOGo.Common']);
}
angular.module('SOGo.MailerUI')
.constant('sgMailbox_PRELOAD', {
LOOKAHEAD: 50,
SIZE: 100
})
.factory('VirtualMailbox', VirtualMailbox.$factory);
/**
* @memberof VirtualMailbox
* @desc Build the path of the virtual mailbox (or account only).
* @param {string} accountId - the account ID
* @returns a string representing the path relative to the mail module
*/
VirtualMailbox.$absolutePath = function(accountId) {
return [accountId, "virtual"].join('/');
};
/**
* @function init
* @memberof Mailbox.prototype
* @desc Extend instance with new data and compute additional attributes.
* @param {object} data - attributes of mailbox
*/
VirtualMailbox.prototype.init = function(data) {
this.$isLoading = false;
this.$mailboxes = [];
this.uidsMap = {};
angular.extend(this, data);
this.id = this.$id();
};
VirtualMailbox.prototype.setMailboxes = function(data) {
this.$mailboxes = data;
_.each(this.$mailboxes, function(mailbox) {
mailbox.$messages = [];
mailbox.uidsMap = {};
});
};
VirtualMailbox.prototype.startSearch = function(match, params) {
var _this = this,
search = VirtualMailbox.$q.when();
this.$isLoading = true;
_.each(this.$mailboxes, function(mailbox) {
search = search.then(function() {
if (_this.$isLoading) {
console.log("searching mailbox " + mailbox.path);
return mailbox.$filter( {sort: "date", asc: false, match: match}, params);
}
});
});
search.finally(function() { _this.$isLoading = false; });
};
VirtualMailbox.prototype.stopSearch = function() {
console.log("stopping search...");
this.$isLoading = false;
};
/**
* @function getLength
* @memberof Mailbox.prototype
* @desc Used by md-virtual-repeat / md-on-demand
* @returns the number of items in the mailbox
*/
VirtualMailbox.prototype.getLength = function() {
var len = 0;
if (!angular.isDefined(this.$mailboxes))
return len;
_.each(this.$mailboxes, function(mailbox) {
len += mailbox.$messages.length;
});
return len;
};
/**
* @function getItemAtIndex
* @memberof Mailbox.prototype
* @desc Used by md-virtual-repeat / md-on-demand
* @returns the message as the specified index
*/
VirtualMailbox.prototype.getItemAtIndex = function(index) {
var i, j, k, mailbox, message;
if (angular.isDefined(this.$mailboxes) && index >= 0) {
i = 0;
for (j = 0; j < this.$mailboxes.length; j++) {
mailbox = this.$mailboxes[j];
for (k = 0; k < mailbox.$messages.length; i++, k++) {
message = mailbox.$messages[k];
if (i == index) {
return message;
}
}
}
}
return null;
};
/**
* @function $id
* @memberof VirtualMailbox.prototype
* @desc Build the unique ID to identified the mailbox.
* @returns a string representing the path relative to the mail module
*/
VirtualMailbox.prototype.$id = function() {
return VirtualMailbox.$absolutePath(this.$account.id);
};
/**
* @function $selectedCount
* @memberof VirtualMailbox.prototype
* @desc Return the number of messages selected by the user.
* @returns the number of selected messages
*/
VirtualMailbox.prototype.$selectedCount = function() {
// TODO
return 0;
};
/**
* @function $flagMessages
* @memberof VirtualMailbox.prototype
* @desc Add or remove a flag on a message set
* @returns a promise of the HTTP operation
*/
VirtualMailbox.prototype.$flagMessages = function(uids, flags, operation) {
// TODO
// var data = {msgUIDs: uids,
// flags: flags,
// operation: operation};
// return VirtualMailbox.$$resource.post(this.id, 'addOrRemoveLabel', data);
};
/**
* @function $deleteMessages
* @memberof VirtualMailbox.prototype
* @desc Delete multiple messages from mailbox.
* @return a promise of the HTTP operation
*/
VirtualMailbox.prototype.$deleteMessages = function(uids) {
// TODO
//return VirtualMailbox.$$resource.post(this.id, 'batchDelete', {uids: uids});
};
/**
* @function $copyMessages
* @memberof VirtualMailbox.prototype
* @desc Copy multiple messages from the current mailbox to a target one
* @return a promise of the HTTP operation
*/
VirtualMailbox.prototype.$copyMessages = function(uids, folder) {
// TODO
//return VirtualMailbox.$$resource.post(this.id, 'copyMessages', {uids: uids, folder: folder});
};
/**
* @function $moveMessages
* @memberof VirtualMailbox.prototype
* @desc Move multiple messages from the current mailbox to a target one
* @return a promise of the HTTP operation
*/
VirtualMailbox.prototype.$moveMessages = function(uids, folder) {
// TODO
//return VirtualMailbox.$$resource.post(this.id, 'moveMessages', {uids: uids, folder: folder});
};
})();