2015-05-06 04:06:13 +02:00
|
|
|
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ngInject
|
|
|
|
*/
|
2016-10-03 17:44:51 +02:00
|
|
|
AddressBookController.$inject = ['$scope', '$q', '$window', '$state', '$timeout', '$mdDialog', '$mdToast', 'Account', 'Card', 'AddressBook', 'sgFocus', 'Dialog', 'sgSettings', 'sgHotkeys', 'stateAddressbooks', 'stateAddressbook'];
|
|
|
|
function AddressBookController($scope, $q, $window, $state, $timeout, $mdDialog, $mdToast, Account, Card, AddressBook, focus, Dialog, Settings, sgHotkeys, stateAddressbooks, stateAddressbook) {
|
2016-09-27 21:19:24 +02:00
|
|
|
var vm = this, hotkeys = [];
|
2015-05-06 04:06:13 +02:00
|
|
|
|
2015-05-28 19:48:45 +02:00
|
|
|
AddressBook.selectedFolder = stateAddressbook;
|
|
|
|
|
2015-09-15 03:35:34 +02:00
|
|
|
vm.service = AddressBook;
|
2015-05-28 19:48:45 +02:00
|
|
|
vm.selectedFolder = stateAddressbook;
|
|
|
|
vm.selectCard = selectCard;
|
2015-09-10 15:19:28 +02:00
|
|
|
vm.toggleCardSelection = toggleCardSelection;
|
2015-05-28 19:48:45 +02:00
|
|
|
vm.newComponent = newComponent;
|
|
|
|
vm.unselectCards = unselectCards;
|
|
|
|
vm.confirmDeleteSelectedCards = confirmDeleteSelectedCards;
|
2015-08-10 15:48:47 +02:00
|
|
|
vm.copySelectedCards = copySelectedCards;
|
2016-08-05 22:08:04 +02:00
|
|
|
vm.moveSelectedCards = moveSelectedCards;
|
2015-08-05 21:04:47 +02:00
|
|
|
vm.selectAll = selectAll;
|
2015-07-20 20:24:36 +02:00
|
|
|
vm.sort = sort;
|
|
|
|
vm.sortedBy = sortedBy;
|
2016-10-03 17:44:51 +02:00
|
|
|
vm.searchMode = searchMode;
|
2015-07-20 21:03:29 +02:00
|
|
|
vm.cancelSearch = cancelSearch;
|
2015-08-27 17:01:23 +02:00
|
|
|
vm.newMessage = newMessage;
|
|
|
|
vm.newMessageWithSelectedCards = newMessageWithSelectedCards;
|
|
|
|
vm.newMessageWithRecipient = newMessageWithRecipient;
|
2016-03-08 19:20:34 +01:00
|
|
|
vm.mode = { search: false, multiple: 0 };
|
2016-09-27 21:19:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
_registerHotkeys(hotkeys);
|
|
|
|
|
|
|
|
$scope.$on('$destroy', function() {
|
|
|
|
// Deregister hotkeys
|
|
|
|
_.forEach(hotkeys, function(key) {
|
|
|
|
sgHotkeys.deregisterHotkey(key);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
function _registerHotkeys(keys) {
|
2016-10-03 17:44:51 +02:00
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: l('hotkey_search'),
|
|
|
|
description: l('Search'),
|
|
|
|
callback: searchMode
|
|
|
|
}));
|
2016-09-27 21:19:24 +02:00
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: l('key_create_card'),
|
|
|
|
description: l('Create a new address book card'),
|
|
|
|
callback: angular.bind(vm, newComponent, 'card')
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: l('key_create_list'),
|
|
|
|
description: l('Create a new list'),
|
|
|
|
callback: angular.bind(vm, newComponent, 'list')
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'space',
|
|
|
|
description: l('Toggle item'),
|
|
|
|
callback: toggleCardSelection
|
|
|
|
}));
|
2016-11-10 16:34:31 +01:00
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'shift+space',
|
|
|
|
description: l('Toggle range of items'),
|
|
|
|
callback: toggleCardSelection
|
|
|
|
}));
|
2016-09-27 21:19:24 +02:00
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'up',
|
|
|
|
description: l('View next item'),
|
|
|
|
callback: _nextCard
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'down',
|
|
|
|
description: l('View previous item'),
|
|
|
|
callback: _previousCard
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'shift+up',
|
|
|
|
description: l('Add next item to selection'),
|
|
|
|
callback: _addNextCardToSelection
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'shift+down',
|
|
|
|
description: l('Add previous item to selection'),
|
|
|
|
callback: _addPreviousCardToSelection
|
|
|
|
}));
|
|
|
|
keys.push(sgHotkeys.createHotkey({
|
|
|
|
key: 'backspace',
|
|
|
|
description: l('Delete selected card or address book'),
|
|
|
|
callback: confirmDeleteSelectedCards
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Register the hotkeys
|
|
|
|
_.forEach(keys, function(key) {
|
|
|
|
sgHotkeys.registerHotkey(key);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-05-28 19:48:45 +02:00
|
|
|
function selectCard(card) {
|
2016-06-06 16:32:45 +02:00
|
|
|
$state.go('app.addressbook.card.view', {cardId: card.id});
|
2015-05-28 19:48:45 +02:00
|
|
|
}
|
2016-09-27 21:19:24 +02:00
|
|
|
|
2015-09-10 15:19:28 +02:00
|
|
|
function toggleCardSelection($event, card) {
|
2016-11-10 16:34:31 +01:00
|
|
|
var folder = vm.selectedFolder,
|
|
|
|
selectedIndex, nextSelectedIndex, i;
|
|
|
|
|
|
|
|
if (!card)
|
|
|
|
card = folder.$selectedCard();
|
2015-09-10 15:19:28 +02:00
|
|
|
card.selected = !card.selected;
|
2016-03-08 19:20:34 +01:00
|
|
|
vm.mode.multiple += card.selected? 1 : -1;
|
2016-11-10 16:34:31 +01:00
|
|
|
|
|
|
|
// Select closest range of cards when shift key is pressed
|
|
|
|
if ($event.shiftKey && folder.$selectedCount() > 1) {
|
|
|
|
selectedIndex = folder.idsMap[card.id];
|
|
|
|
// Search for next selected card above
|
|
|
|
nextSelectedIndex = selectedIndex - 2;
|
|
|
|
while (nextSelectedIndex >= 0 &&
|
|
|
|
!folder.$cards[nextSelectedIndex].selected)
|
|
|
|
nextSelectedIndex--;
|
|
|
|
if (nextSelectedIndex < 0) {
|
|
|
|
// Search for next selected card bellow
|
|
|
|
nextSelectedIndex = selectedIndex + 2;
|
|
|
|
while (nextSelectedIndex < folder.getLength() &&
|
|
|
|
!folder.$cards[nextSelectedIndex].selected)
|
|
|
|
nextSelectedIndex++;
|
|
|
|
}
|
|
|
|
if (nextSelectedIndex >= 0 && nextSelectedIndex < folder.getLength()) {
|
|
|
|
for (i = Math.min(selectedIndex, nextSelectedIndex);
|
|
|
|
i <= Math.max(selectedIndex, nextSelectedIndex);
|
|
|
|
i++)
|
|
|
|
folder.$cards[i].selected = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-10 15:19:28 +02:00
|
|
|
$event.preventDefault();
|
|
|
|
$event.stopPropagation();
|
|
|
|
}
|
|
|
|
|
2016-06-10 21:05:35 +02:00
|
|
|
function newComponent(type) {
|
|
|
|
$state.go('app.addressbook.new', { contactType: type });
|
2015-05-28 19:48:45 +02:00
|
|
|
}
|
2015-05-08 21:47:09 +02:00
|
|
|
|
2015-05-28 19:48:45 +02:00
|
|
|
function unselectCards() {
|
2016-03-08 19:20:34 +01:00
|
|
|
_.forEach(vm.selectedFolder.$cards, function(card) {
|
|
|
|
card.selected = false;
|
|
|
|
});
|
|
|
|
vm.mode.multiple = 0;
|
2015-05-28 19:48:45 +02:00
|
|
|
}
|
2016-09-27 21:19:24 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* User has pressed up arrow key
|
|
|
|
*/
|
|
|
|
function _nextCard($event) {
|
|
|
|
var index = vm.selectedFolder.$selectedCardIndex();
|
|
|
|
|
2016-10-03 17:27:57 +02:00
|
|
|
if (angular.isDefined(index)) {
|
2016-09-27 21:19:24 +02:00
|
|
|
index--;
|
2016-10-03 17:27:57 +02:00
|
|
|
if (vm.selectedFolder.$topIndex > 0)
|
|
|
|
vm.selectedFolder.$topIndex--;
|
|
|
|
}
|
|
|
|
else {
|
2016-11-10 16:34:31 +01:00
|
|
|
// No card is selected, show oldest card
|
2016-09-27 21:19:24 +02:00
|
|
|
index = vm.selectedFolder.$cards.length() - 1;
|
2016-10-03 17:27:57 +02:00
|
|
|
vm.selectedFolder.$topIndex = vm.selectedFolder.getLength();
|
|
|
|
}
|
2016-09-27 21:19:24 +02:00
|
|
|
|
|
|
|
if (index > -1)
|
|
|
|
selectCard(vm.selectedFolder.$cards[index]);
|
|
|
|
|
|
|
|
$event.preventDefault();
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* User has pressed the down arrow key
|
|
|
|
*/
|
|
|
|
function _previousCard($event) {
|
|
|
|
var index = vm.selectedFolder.$selectedCardIndex();
|
|
|
|
|
2016-10-03 17:27:57 +02:00
|
|
|
if (angular.isDefined(index)) {
|
2016-09-27 21:19:24 +02:00
|
|
|
index++;
|
2016-10-03 17:27:57 +02:00
|
|
|
if (vm.selectedFolder.$topIndex < vm.selectedFolder.$cards.length)
|
|
|
|
vm.selectedFolder.$topIndex++;
|
|
|
|
}
|
2016-09-27 21:19:24 +02:00
|
|
|
else
|
2016-11-10 16:34:31 +01:00
|
|
|
// No card is selected, show newest
|
2016-09-27 21:19:24 +02:00
|
|
|
index = 0;
|
|
|
|
|
|
|
|
if (index < vm.selectedFolder.$cards.length)
|
|
|
|
selectCard(vm.selectedFolder.$cards[index]);
|
|
|
|
else
|
|
|
|
index = -1;
|
|
|
|
|
|
|
|
$event.preventDefault();
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
function _addNextCardToSelection($event) {
|
|
|
|
var index;
|
|
|
|
|
|
|
|
if (vm.selectedFolder.hasSelectedCard()) {
|
|
|
|
index = _nextCard($event);
|
|
|
|
if (index >= 0)
|
|
|
|
toggleCardSelection($event, vm.selectedFolder.$cards[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function _addPreviousCardToSelection($event) {
|
|
|
|
var index;
|
|
|
|
|
|
|
|
if (vm.selectedFolder.hasSelectedCard()) {
|
|
|
|
index = _previousCard($event);
|
|
|
|
if (index >= 0)
|
|
|
|
toggleCardSelection($event, vm.selectedFolder.$cards[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function confirmDeleteSelectedCards($event) {
|
|
|
|
var selectedCards = vm.selectedFolder.$selectedCards();
|
|
|
|
|
|
|
|
if (_.size(selectedCards) > 0)
|
|
|
|
Dialog.confirm(l('Warning'),
|
|
|
|
l('Are you sure you want to delete the selected contacts?'),
|
|
|
|
{ ok: l('Delete') })
|
2015-05-08 21:47:09 +02:00
|
|
|
.then(function() {
|
|
|
|
// User confirmed the deletion
|
2016-07-19 22:31:48 +02:00
|
|
|
vm.selectedFolder.$deleteCards(selectedCards).then(function() {
|
2016-07-20 17:07:57 +02:00
|
|
|
vm.mode.multiple = 0;
|
2016-07-19 22:31:48 +02:00
|
|
|
if (!vm.selectedFolder.selectedCard)
|
|
|
|
$state.go('app.addressbook');
|
|
|
|
});
|
2015-05-08 21:47:09 +02:00
|
|
|
});
|
2016-09-27 21:19:24 +02:00
|
|
|
|
|
|
|
$event.preventDefault();
|
2015-05-28 19:48:45 +02:00
|
|
|
}
|
2015-07-20 20:24:36 +02:00
|
|
|
|
2016-08-05 22:08:04 +02:00
|
|
|
/**
|
|
|
|
* @see AddressBooksController.dragSelectedCards
|
|
|
|
*/
|
|
|
|
function _selectedCardsOperation(operation, dstId) {
|
|
|
|
var srcFolder, allCards, cards, ids, clearCardView, promise, success;
|
|
|
|
|
|
|
|
srcFolder = vm.selectedFolder;
|
|
|
|
clearCardView = false;
|
|
|
|
allCards = srcFolder.$selectedCards();
|
|
|
|
cards = _.filter(allCards, function(card) {
|
|
|
|
return card.$isCard();
|
2015-08-10 15:48:47 +02:00
|
|
|
});
|
2016-08-05 22:08:04 +02:00
|
|
|
|
|
|
|
if (cards.length != allCards.length)
|
|
|
|
$mdToast.show(
|
|
|
|
$mdToast.simple()
|
|
|
|
.content(l("Lists can't be moved or copied."))
|
|
|
|
.position('top right')
|
|
|
|
.hideDelay(2000));
|
|
|
|
|
|
|
|
if (cards.length) {
|
|
|
|
if (operation == 'copy') {
|
|
|
|
promise = srcFolder.$copyCards(cards, dstId);
|
|
|
|
success = l('%{0} card(s) copied', cards.length);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
promise = srcFolder.$moveCards(cards, dstId);
|
|
|
|
success = l('%{0} card(s) moved', cards.length);
|
|
|
|
// Check if currently displayed card will be moved
|
|
|
|
ids = _.map(cards, 'id');
|
|
|
|
clearCardView = (srcFolder.selectedCard && ids.indexOf(srcFolder.selectedCard) >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show success toast when action succeeds
|
|
|
|
promise.then(function() {
|
|
|
|
if (clearCardView)
|
|
|
|
$state.go('app.addressbook');
|
|
|
|
$mdToast.show(
|
|
|
|
$mdToast.simple()
|
|
|
|
.content(success)
|
|
|
|
.position('top right')
|
|
|
|
.hideDelay(2000));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function copySelectedCards(folder) {
|
|
|
|
_selectedCardsOperation('copy', folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
function moveSelectedCards(folder) {
|
|
|
|
_selectedCardsOperation('move', folder);
|
2015-08-10 15:48:47 +02:00
|
|
|
}
|
|
|
|
|
2015-08-05 21:04:47 +02:00
|
|
|
function selectAll() {
|
2016-03-03 19:38:54 +01:00
|
|
|
_.forEach(vm.selectedFolder.$cards, function(card) {
|
2015-08-05 21:04:47 +02:00
|
|
|
card.selected = true;
|
|
|
|
});
|
2016-03-08 19:20:34 +01:00
|
|
|
vm.mode.multiple = vm.selectedFolder.$cards.length;
|
2015-08-05 21:04:47 +02:00
|
|
|
}
|
|
|
|
|
2015-07-20 20:24:36 +02:00
|
|
|
function sort(field) {
|
|
|
|
vm.selectedFolder.$filter('', { sort: field });
|
|
|
|
}
|
|
|
|
|
|
|
|
function sortedBy(field) {
|
2015-08-14 21:22:59 +02:00
|
|
|
return AddressBook.$query.sort == field;
|
2015-07-20 20:24:36 +02:00
|
|
|
}
|
2015-07-20 21:03:29 +02:00
|
|
|
|
2016-10-03 17:44:51 +02:00
|
|
|
function searchMode() {
|
|
|
|
vm.mode.search = true;
|
|
|
|
focus('search');
|
|
|
|
}
|
|
|
|
|
2015-07-20 21:03:29 +02:00
|
|
|
function cancelSearch() {
|
|
|
|
vm.mode.search = false;
|
|
|
|
vm.selectedFolder.$filter('');
|
|
|
|
}
|
2015-08-27 17:01:23 +02:00
|
|
|
|
2017-01-26 19:27:13 +01:00
|
|
|
function newMessage($event, recipients, recipientsField) {
|
2015-08-27 17:01:23 +02:00
|
|
|
Account.$findAll().then(function(accounts) {
|
2016-05-16 20:23:01 +02:00
|
|
|
var account = _.find(accounts, function(o) {
|
2015-08-27 17:01:23 +02:00
|
|
|
if (o.id === 0)
|
|
|
|
return o;
|
2016-05-16 20:23:01 +02:00
|
|
|
});
|
2015-08-27 17:01:23 +02:00
|
|
|
|
|
|
|
// We must initialize the Account with its mailbox
|
|
|
|
// list before proceeding with message's creation
|
|
|
|
account.$getMailboxes().then(function(mailboxes) {
|
|
|
|
account.$newMessage().then(function(message) {
|
2017-01-26 19:27:13 +01:00
|
|
|
switch(recipientsField) {
|
|
|
|
case 0:
|
|
|
|
angular.extend(message.editable, { to: recipients });
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
angular.extend(message.editable, { cc: recipients });
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
angular.extend(message.editable, { bcc: recipients });
|
|
|
|
}
|
2015-08-27 17:01:23 +02:00
|
|
|
$mdDialog.show({
|
|
|
|
parent: angular.element(document.body),
|
|
|
|
targetEvent: $event,
|
|
|
|
clickOutsideToClose: false,
|
|
|
|
escapeToClose: false,
|
|
|
|
templateUrl: '../Mail/UIxMailEditor',
|
|
|
|
controller: 'MessageEditorController',
|
|
|
|
controllerAs: 'editor',
|
|
|
|
locals: {
|
2016-05-16 20:23:01 +02:00
|
|
|
stateAccount: account,
|
2016-05-19 21:58:26 +02:00
|
|
|
stateMessage: message
|
2015-08-27 17:01:23 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function newMessageWithRecipient($event, recipient, fn) {
|
2016-05-19 21:58:26 +02:00
|
|
|
var recipients = [fn + ' <' + recipient + '>'];
|
2017-01-26 19:27:13 +01:00
|
|
|
vm.newMessage($event, recipients, 0);
|
2015-12-08 16:35:26 +01:00
|
|
|
$event.stopPropagation();
|
|
|
|
$event.preventDefault();
|
2015-08-27 17:01:23 +02:00
|
|
|
}
|
|
|
|
|
2017-01-26 19:27:13 +01:00
|
|
|
function newMessageWithSelectedCards($event, recipientsField) {
|
2016-02-26 22:24:18 +01:00
|
|
|
var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; });
|
2015-08-27 17:01:23 +02:00
|
|
|
var promises = [], recipients = [];
|
|
|
|
|
2016-03-03 19:38:54 +01:00
|
|
|
_.forEach(selectedCards, function(card) {
|
2016-05-19 22:34:42 +02:00
|
|
|
if (card.$isList({expandable: true})) {
|
2015-08-27 17:01:23 +02:00
|
|
|
// If the list's members were already fetch, use them
|
|
|
|
if (angular.isDefined(card.refs) && card.refs.length) {
|
2016-03-03 19:38:54 +01:00
|
|
|
_.forEach(card.refs, function(ref) {
|
2015-08-27 17:01:23 +02:00
|
|
|
if (ref.email.length)
|
2016-05-19 22:34:42 +02:00
|
|
|
recipients.push(ref.$shortFormat());
|
2015-08-27 17:01:23 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
2016-05-30 18:29:58 +02:00
|
|
|
promises.push(card.$reload().then(function(card) {
|
|
|
|
_.forEach(card.refs, function(ref) {
|
|
|
|
if (ref.email.length)
|
|
|
|
recipients.push(ref.$shortFormat());
|
2015-08-27 17:01:23 +02:00
|
|
|
});
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2016-05-19 22:34:42 +02:00
|
|
|
else if (card.c_mail.length) {
|
|
|
|
recipients.push(card.$shortFormat());
|
|
|
|
}
|
2015-08-27 17:01:23 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
$q.all(promises).then(function() {
|
2016-05-19 22:34:42 +02:00
|
|
|
recipients = _.uniq(recipients);
|
2015-08-27 17:01:23 +02:00
|
|
|
if (recipients.length)
|
2017-01-26 19:27:13 +01:00
|
|
|
vm.newMessage($event, recipients, recipientsField);
|
2015-08-27 17:01:23 +02:00
|
|
|
});
|
|
|
|
}
|
2015-05-08 21:47:09 +02:00
|
|
|
}
|
2015-05-06 04:06:13 +02:00
|
|
|
|
|
|
|
angular
|
2016-09-27 21:19:24 +02:00
|
|
|
.module('SOGo.ContactsUI')
|
|
|
|
.controller('AddressBookController', AddressBookController);
|
2015-05-06 04:06:13 +02:00
|
|
|
})();
|