From 721428c88f9caf19753986d843eee279b851723c Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 4 Jul 2017 10:09:22 -0400 Subject: [PATCH] (js) Create list from selected cards Fixes #3561 --- NEWS | 1 + .../ContactsUI/UIxContactFoldersView.wox | 5 + .../js/Contacts/AddressBookController.js | 174 ++++++++++-------- .../js/Contacts/Card.service.js | 6 +- .../js/Contacts/Contacts.app.js | 5 +- 5 files changed, 113 insertions(+), 78 deletions(-) diff --git a/NEWS b/NEWS index 09da3e02f..5e494d86c 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ New features - [web] new images viewer in Mail module + - [web] create list from selected cards (#3561) - [eas] initial EAS v16 and email drafts support - [core] load-testing scripts to evaluate SOGo performance diff --git a/UI/Templates/ContactsUI/UIxContactFoldersView.wox b/UI/Templates/ContactsUI/UIxContactFoldersView.wox index 84a80b4be..a818a4fd2 100644 --- a/UI/Templates/ContactsUI/UIxContactFoldersView.wox +++ b/UI/Templates/ContactsUI/UIxContactFoldersView.wox @@ -386,6 +386,11 @@ + + + + + diff --git a/UI/WebServerResources/js/Contacts/AddressBookController.js b/UI/WebServerResources/js/Contacts/AddressBookController.js index bd0c0942e..732f7785f 100644 --- a/UI/WebServerResources/js/Contacts/AddressBookController.js +++ b/UI/WebServerResources/js/Contacts/AddressBookController.js @@ -10,63 +10,50 @@ function AddressBookController($scope, $q, $window, $state, $timeout, $mdDialog, $mdToast, Account, Card, AddressBook, focus, Dialog, Settings, sgHotkeys, stateAddressbooks, stateAddressbook) { var vm = this, hotkeys = []; - AddressBook.selectedFolder = stateAddressbook; + this.$onInit = function() { + AddressBook.selectedFolder = stateAddressbook; - vm.service = AddressBook; - vm.selectedFolder = stateAddressbook; - vm.selectCard = selectCard; - vm.toggleCardSelection = toggleCardSelection; - vm.newComponent = newComponent; - vm.unselectCards = unselectCards; - vm.confirmDeleteSelectedCards = confirmDeleteSelectedCards; - vm.copySelectedCards = copySelectedCards; - vm.moveSelectedCards = moveSelectedCards; - vm.selectAll = selectAll; - vm.sort = sort; - vm.sortedBy = sortedBy; - vm.searchMode = searchMode; - vm.cancelSearch = cancelSearch; - vm.newMessage = newMessage; - vm.newMessageWithSelectedCards = newMessageWithSelectedCards; - vm.newMessageWithRecipient = newMessageWithRecipient; - vm.mode = { search: false, multiple: 0 }; + this.service = AddressBook; + this.selectedFolder = stateAddressbook; + this.mode = { search: false, multiple: 0 }; - _registerHotkeys(hotkeys); + _registerHotkeys(hotkeys); - $scope.$on('$destroy', function() { - // Deregister hotkeys - _.forEach(hotkeys, function(key) { - sgHotkeys.deregisterHotkey(key); + $scope.$on('$destroy', function() { + // Deregister hotkeys + _.forEach(hotkeys, function(key) { + sgHotkeys.deregisterHotkey(key); + }); }); - }); + }; function _registerHotkeys(keys) { keys.push(sgHotkeys.createHotkey({ key: l('hotkey_search'), description: l('Search'), - callback: searchMode + callback: angular.bind(vm, vm.searchMode) })); keys.push(sgHotkeys.createHotkey({ key: l('key_create_card'), description: l('Create a new address book card'), - callback: angular.bind(vm, newComponent, 'card') + callback: angular.bind(vm, vm.newComponent, 'card') })); keys.push(sgHotkeys.createHotkey({ key: l('key_create_list'), description: l('Create a new list'), - callback: angular.bind(vm, newComponent, 'list') + callback: angular.bind(vm, vm.newComponent, 'list') })); keys.push(sgHotkeys.createHotkey({ key: 'space', description: l('Toggle item'), - callback: toggleCardSelection + callback: angular.bind(vm, vm.toggleCardSelection) })); keys.push(sgHotkeys.createHotkey({ key: 'shift+space', description: l('Toggle range of items'), - callback: toggleCardSelection + callback: angular.bind(vm, vm.toggleCardSelection) })); keys.push(sgHotkeys.createHotkey({ key: 'up', @@ -92,7 +79,7 @@ keys.push(sgHotkeys.createHotkey({ key: hotkey, description: l('Delete selected card or address book'), - callback: confirmDeleteSelectedCards + callback: angular.bind(vm, vm.confirmDeleteSelectedCards) })); }); @@ -102,18 +89,18 @@ }); } - function selectCard(card) { + this.selectCard = function(card) { $state.go('app.addressbook.card.view', {cardId: card.id}); - } + }; - function toggleCardSelection($event, card) { - var folder = vm.selectedFolder, + this.toggleCardSelection = function($event, card) { + var folder = this.selectedFolder, selectedIndex, nextSelectedIndex, i; if (!card) card = folder.$selectedCard(); card.selected = !card.selected; - vm.mode.multiple += card.selected? 1 : -1; + this.mode.multiple += card.selected? 1 : -1; // Select closest range of cards when shift key is pressed if ($event.shiftKey && folder.$selectedCount() > 1) { @@ -140,18 +127,18 @@ $event.preventDefault(); $event.stopPropagation(); - } + }; - function newComponent(type) { + this.newComponent = function(type) { $state.go('app.addressbook.new', { contactType: type }); - } + }; - function unselectCards() { - _.forEach(vm.selectedFolder.$cards, function(card) { + this.unselectCards = function() { + _.forEach(this.selectedFolder.$cards, function(card) { card.selected = false; }); - vm.mode.multiple = 0; - } + this.mode.multiple = 0; + }; /** * User has pressed up arrow key @@ -171,7 +158,7 @@ } if (index > -1) - selectCard(vm.selectedFolder.$cards[index]); + vm.selectCard(vm.selectedFolder.$cards[index]); $event.preventDefault(); @@ -194,7 +181,7 @@ index = 0; if (index < vm.selectedFolder.$cards.length) - selectCard(vm.selectedFolder.$cards[index]); + vm.selectCard(vm.selectedFolder.$cards[index]); else index = -1; @@ -223,8 +210,8 @@ } } - function confirmDeleteSelectedCards($event) { - var selectedCards = vm.selectedFolder.$selectedCards(); + this.confirmDeleteSelectedCards = function($event) { + var selectedCards = this.selectedFolder.$selectedCards(); if (_.size(selectedCards) > 0) Dialog.confirm(l('Warning'), @@ -240,7 +227,7 @@ }); $event.preventDefault(); - } + }; /** * @see AddressBooksController.dragSelectedCards @@ -288,40 +275,40 @@ } } - function copySelectedCards(folder) { + this.copySelectedCards = function(folder) { _selectedCardsOperation('copy', folder); - } + }; - function moveSelectedCards(folder) { + this.moveSelectedCards = function(folder) { _selectedCardsOperation('move', folder); - } + }; - function selectAll() { - _.forEach(vm.selectedFolder.$cards, function(card) { + this.selectAll = function() { + _.forEach(this.selectedFolder.$cards, function(card) { card.selected = true; }); - vm.mode.multiple = vm.selectedFolder.$cards.length; - } + this.mode.multiple = this.selectedFolder.$cards.length; + }; - function sort(field) { - vm.selectedFolder.$filter('', { sort: field }); - } + this.sort = function(field) { + this.selectedFolder.$filter('', { sort: field }); + }; - function sortedBy(field) { + this.sortedBy = function(field) { return AddressBook.$query.sort == field; - } + }; - function searchMode() { + this.searchMode = function() { vm.mode.search = true; focus('search'); - } + }; - function cancelSearch() { - vm.mode.search = false; - vm.selectedFolder.$filter(''); - } + this.cancelSearch = function() { + this.mode.search = false; + this.selectedFolder.$filter(''); + }; - function newMessage($event, recipients, recipientsField) { + this.newMessage = function($event, recipients, recipientsField) { Account.$findAll().then(function(accounts) { var account = _.find(accounts, function(o) { if (o.id === 0) @@ -349,17 +336,17 @@ }); }); }); - } + }; - function newMessageWithRecipient($event, recipient, fn) { + this.newMessageWithRecipient = function($event, recipient, fn) { var recipients = [fn + ' <' + recipient + '>']; - vm.newMessage($event, recipients, 'to'); + this.newMessage($event, recipients, 'to'); $event.stopPropagation(); $event.preventDefault(); - } + }; - function newMessageWithSelectedCards($event, recipientsField) { - var selectedCards = _.filter(vm.selectedFolder.$cards, function(card) { return card.selected; }); + this.newMessageWithSelectedCards = function($event, recipientsField) { + var selectedCards = _.filter(this.selectedFolder.$cards, function(card) { return card.selected; }); var promises = [], recipients = []; _.forEach(selectedCards, function(card) { @@ -390,7 +377,44 @@ if (recipients.length) vm.newMessage($event, recipients, recipientsField); }); - } + }; + + this.newListWithSelectedCards = function() { + var selectedCards = _.filter(this.selectedFolder.$cards, function(card) { return card.selected; }); + var promises = [], refs = []; + + _.forEach(selectedCards, function(card) { + if (card.$isList({expandable: true})) { + // If the list's members were already fetch, use them + if (angular.isDefined(card.refs) && card.refs.length) { + _.forEach(card.refs, function(ref) { + if (ref.email.length) + refs.push(ref); + }); + } + else { + promises.push(card.$reload().then(function(card) { + _.forEach(card.refs, function(ref) { + if (ref.email.length) + refs.push(ref); + }); + })); + } + } + else if (card.$$email && card.$$email.length) { + refs.push(card); + } + }); + + $q.all(promises).then(function() { + refs = _.uniqBy(_.map(refs, function(o) { + return { reference: o.id || o.reference, email: o.$$email || o.email }; + }), 'reference'); + if (refs.length) + $state.go('app.addressbook.new', { contactType: 'list', refs: refs }); + }); + }; + } angular diff --git a/UI/WebServerResources/js/Contacts/Card.service.js b/UI/WebServerResources/js/Contacts/Card.service.js index 913b36756..f396f1441 100644 --- a/UI/WebServerResources/js/Contacts/Card.service.js +++ b/UI/WebServerResources/js/Contacts/Card.service.js @@ -136,8 +136,10 @@ Card.prototype.init = function(data, partial) { var _this = this; - this.refs = []; - this.categories = []; + if (angular.isUndefined(this.refs)) + this.refs = []; + if (angular.isUndefined(this.categories)) + this.categories = []; this.c_screenname = null; angular.extend(this, data); if (!this.$$fullname) diff --git a/UI/WebServerResources/js/Contacts/Contacts.app.js b/UI/WebServerResources/js/Contacts/Contacts.app.js index cc38d019d..33d2fefe6 100644 --- a/UI/WebServerResources/js/Contacts/Contacts.app.js +++ b/UI/WebServerResources/js/Contacts/Contacts.app.js @@ -43,6 +43,9 @@ }) .state('app.addressbook.new', { url: '/{contactType:(?:card|list)}/new', + params: { + refs: { array: true } + }, views: { card: { templateUrl: 'UIxContactEditorTemplate', // UI/Templates/Contacts/UIxContactEditorTemplate.wox @@ -123,7 +126,7 @@ stateNewCard.$inject = ['$stateParams', 'stateAddressbook', 'Card']; function stateNewCard($stateParams, stateAddressbook, Card) { var tag = 'v' + $stateParams.contactType, - card = new Card({ pid: $stateParams.addressbookId, c_component: tag }); + card = new Card({ pid: $stateParams.addressbookId, c_component: tag, refs: $stateParams.refs }); stateAddressbook.selectedCard = true; return card; }