diff --git a/NEWS b/NEWS index c53a4cd97..be294b0b0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +4.0.6 (YYYY-MM-DD) +------------------ + +Enhancements +- [web] create card from sender or recipient address (#3002, #4610) + 4.0.5 (2019-01-09) ------------------ diff --git a/UI/MailerUI/English.lproj/Localizable.strings b/UI/MailerUI/English.lproj/Localizable.strings index 64c333ec5..8dcd1c00a 100644 --- a/UI/MailerUI/English.lproj/Localizable.strings +++ b/UI/MailerUI/English.lproj/Localizable.strings @@ -179,6 +179,7 @@ /* Address Popup menu */ "Add to Address Book..." = "Add to Address Book..."; +"Successfully created card" = "Successfully created card"; "Compose Mail To" = "Compose Mail To"; "Create Filter From Message..." = "Create Filter From Message..."; diff --git a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox index b048c5ac5..21f2d218d 100644 --- a/UI/Templates/MailerUI/UIxMailFolderTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailFolderTemplate.wox @@ -39,7 +39,7 @@ - + + + + diff --git a/UI/Templates/MailerUI/UIxMailViewTemplate.wox b/UI/Templates/MailerUI/UIxMailViewTemplate.wox index c8831c051..fb49f0296 100644 --- a/UI/Templates/MailerUI/UIxMailViewTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailViewTemplate.wox @@ -127,56 +127,70 @@
-
-
-
-
- person -
- -
- -
+
+
+
+ person +
+ +
-
-
- -
- -
-
- - - -
+
+
+
+ +
+
-
- -
- - - - - - -
+
+ + + {{ $chip.name || $chip.email }} + +
+
+ +
+ + + {{ $chip.name || $chip.email }} + + +
+ + + +
diff --git a/UI/WebServerResources/js/Contacts/AddressBook.service.js b/UI/WebServerResources/js/Contacts/AddressBook.service.js index 0485ef20b..329393071 100644 --- a/UI/WebServerResources/js/Contacts/AddressBook.service.js +++ b/UI/WebServerResources/js/Contacts/AddressBook.service.js @@ -45,6 +45,9 @@ $Preferences: Preferences, $query: {value: '', sort: 'c_cn', asc: 1}, activeUser: Settings.activeUser(), + $addressbooks: [], + $subscriptions: [], + $remotes: [], selectedFolder: null, $refreshTimeout: null }); @@ -159,10 +162,10 @@ */ AddressBook.$findAll = function(data) { var _this = this; - if (data) { - this.$addressbooks = []; - this.$subscriptions = []; - this.$remotes = []; + if (data && data.length) { + this.$addressbooks.splice(0, this.$addressbooks.length); + this.$subscriptions.splice(0, this.$subscriptions.length); + this.$remotes.splice(0, this.$remotes.length); // Instanciate AddressBook objects angular.forEach(data, function(o, i) { var addressbook = new AddressBook(o); @@ -174,6 +177,12 @@ _this.$addressbooks.push(addressbook); }); } + else if (angular.isArray(data)) { // empty array + return AddressBook.$$resource.fetch('addressbooksList').then(function(data) { + return AddressBook.$findAll(data.addressbooks); + }); + } + return _.union(this.$addressbooks, this.$subscriptions, this.$remotes); }; diff --git a/UI/WebServerResources/js/Mailer/MessageController.js b/UI/WebServerResources/js/Mailer/MessageController.js index 7dc4b78ec..bfc6e6b0c 100644 --- a/UI/WebServerResources/js/Mailer/MessageController.js +++ b/UI/WebServerResources/js/Mailer/MessageController.js @@ -6,8 +6,8 @@ /** * @ngInject */ - MessageController.$inject = ['$window', '$scope', '$q', '$state', '$mdMedia', '$mdDialog', 'sgConstant', 'stateAccounts', 'stateAccount', 'stateMailbox', 'stateMessage', 'sgHotkeys', 'encodeUriFilter', 'sgSettings', 'ImageGallery', 'sgFocus', 'Dialog', 'Preferences', 'Calendar', 'Component', 'Account', 'Mailbox', 'Message']; - function MessageController($window, $scope, $q, $state, $mdMedia, $mdDialog, sgConstant, stateAccounts, stateAccount, stateMailbox, stateMessage, sgHotkeys, encodeUriFilter, sgSettings, ImageGallery, focus, Dialog, Preferences, Calendar, Component, Account, Mailbox, Message) { + MessageController.$inject = ['$window', '$scope', '$q', '$state', '$mdMedia', '$mdDialog', '$mdPanel', 'sgConstant', 'stateAccounts', 'stateAccount', 'stateMailbox', 'stateMessage', 'sgHotkeys', 'encodeUriFilter', 'sgSettings', 'ImageGallery', 'sgFocus', 'Dialog', 'Preferences', 'Calendar', 'Component', 'Account', 'Mailbox', 'Message', 'AddressBook', 'Card']; + function MessageController($window, $scope, $q, $state, $mdMedia, $mdDialog, $mdPanel, sgConstant, stateAccounts, stateAccount, stateMailbox, stateMessage, sgHotkeys, encodeUriFilter, sgSettings, ImageGallery, focus, Dialog, Preferences, Calendar, Component, Account, Mailbox, Message, AddressBook, Card) { var vm = this, popupWindow = null, hotkeys = []; this.$onInit = function() { @@ -27,7 +27,8 @@ this.service = Message; this.tags = { searchText: '', selected: '' }; this.showFlags = stateMessage.flags && stateMessage.flags.length > 0; - this.$showDetailedRecipients = false; + this.$alwaysShowDetailedRecipients = (!stateMessage.to || stateMessage.to.length < 5) && (!stateMessage.cc || stateMessage.cc.length < 5); + this.$showDetailedRecipients = this.$alwaysShowDetailedRecipients; this.showRawSource = false; _registerHotkeys(hotkeys); @@ -197,6 +198,108 @@ $event.preventDefault(); }; + this.focusChip = function($event) { + var chipElement = $event.target; + while (chipElement.tagName !== 'MD-CHIP') { + chipElement = chipElement.parentNode; + } + chipElement.classList.add('md-focused'); + }; + + this.blurChip = function($event) { + var chipElement = $event.target; + while (chipElement.tagName !== 'MD-CHIP') { + chipElement = chipElement.parentNode; + } + chipElement.classList.remove('md-focused'); + if ($event.relatedTarget && $event.relatedTarget.tagName === 'MD-CHIP-TEMPLATE') { + // Moving to another chip; close menu + vm.panel.close(); + } + }; + + this.selectRecipient = function(recipient, $event) { + // Fetch addressbooks list + AddressBook.$findAll([]); + + var targetElement = $event.target; + + var panelPosition = $mdPanel.newPanelPosition() + .relativeTo(targetElement) + .addPanelPosition( + $mdPanel.xPosition.ALIGN_START, + $mdPanel.yPosition.ALIGN_TOPS + ); + + var panelAnimation = $mdPanel.newPanelAnimation() + .openFrom(targetElement) + .duration(100) + .withAnimation($mdPanel.animation.FADE); + + var config = { + attachTo: angular.element(document.body), + locals: { + recipient: recipient, + addressbooks: AddressBook.$addressbooks, + subscriptions: AddressBook.$subscriptions, + newMessage: angular.bind(this, this.newMessage) + }, + bindToController: true, + controller: MenuController, + controllerAs: '$menuCtrl', + position: panelPosition, + animation: panelAnimation, + targetEvent: $event, + templateUrl: 'UIxMailViewRecipientMenu', + trapFocus: true, + clickOutsideToClose: true, + escapeToClose: true, + focusOnOpen: false + }; + + $mdPanel.open(config) + .then(function(panelRef) { + vm.panel = panelRef; + // Automatically close panel when clicking inside of it + panelRef.panelEl.one('click', function() { + panelRef.close(); + }); + }); + + MenuController.$inject = ['mdPanelRef', '$state', '$mdToast']; + function MenuController(mdPanelRef, $state, $mdToast) { + this.onKeyDown = function($event) { + if ($event.which === 9) { // Tab + mdPanelRef.close(); + } + }; + + this.newCard = function(recipient, addressbookId) { + var card = new Card({ + pid: addressbookId, + c_cn: recipient.name, + emails: [{ value: recipient.email }] + }); + card.$id().then(function(id) { + card.$save().then(function() { + // Show success toast when action succeeds + $mdToast.show( + $mdToast.simple() + .content(l('Successfully created card')) + .position('top right') + .hideDelay(2000)); + }); + }); + mdPanelRef.close(); + }; + } + + if (targetElement.tagName === 'A') { + $event.stopPropagation(); + $event.preventDefault(); + } + }; + this.filterMailtoLinks = function($event) { var href, match, to, cc, bcc, subject, body, data; if ($event.target.tagName == 'A' && 'href' in $event.target.attributes) { @@ -382,8 +485,10 @@ }; this.newMessage = function($event, mailto) { - $event.stopPropagation(); - $event.preventDefault(); + if ($event.target.tagName === 'A') { + $event.stopPropagation(); + $event.preventDefault(); + } this.account.$newMessage({ mailto: mailto }).then(function(message) { _showMailEditor($event, message); }); diff --git a/UI/WebServerResources/scss/components/chips/chips.scss b/UI/WebServerResources/scss/components/chips/chips.scss index 3167b59d0..65effc644 100644 --- a/UI/WebServerResources/scss/components/chips/chips.scss +++ b/UI/WebServerResources/scss/components/chips/chips.scss @@ -1,6 +1,11 @@ /// chips.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*- @import 'extends'; +$chip-dense-font-size: rem(1.2) !default; +$chip-dense-height: rem(2.4) !default; +$chip-dense-padding: 0 rem(0.8) 0 rem(0.8) !default; +$chip-dense-margin: rem(0.6) rem(0.6) 0 0 !default; + md-chips { // Remove the line under the tags of the message viewer &.sg-readonly { @@ -9,6 +14,9 @@ md-chips { &.md-focused { box-shadow: none; } + md-chip-template:focus { + outline: 0; + } .md-chip-content { //max-width: initial; // fix bug in ng-material } @@ -25,6 +33,15 @@ md-chips { } } } + + // Small, compact chip + &.sg-dense md-chip { + height: $chip-dense-height; + padding: $chip-dense-padding; + @include rtl(margin, $chip-dense-margin, rtl-value($chip-dense-margin)); + font-size: $chip-dense-font-size; + line-height: $chip-dense-height; + } .sg-chip-progress { border-radius: $chip-height / 2; bottom: 0; diff --git a/UI/WebServerResources/scss/views/MailerUI.scss b/UI/WebServerResources/scss/views/MailerUI.scss index 6ec7d792b..2d5e5c8c6 100644 --- a/UI/WebServerResources/scss/views/MailerUI.scss +++ b/UI/WebServerResources/scss/views/MailerUI.scss @@ -61,6 +61,9 @@ padding-left: $mg; padding-right: $mg; } + md-chip { + cursor: pointer; + } } // Vertical buttons in header area of mail composer dialog