From 68c72f681c132e93395d54e263c23dfba918b4b9 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Thu, 7 Jan 2016 15:43:26 -0500 Subject: [PATCH] (js) Improve message viewer/editor in popup window --- UI/Templates/MailerUI/UIxMailPopupView.wox | 2 +- UI/Templates/MailerUI/UIxMailViewTemplate.wox | 4 +- .../js/Mailer/MailboxController.js | 7 +- .../js/Mailer/Mailer.popup.js | 55 ++++++++--- .../js/Mailer/Message.service.js | 18 +--- .../js/Mailer/MessageController.js | 97 ++++++++++++++++--- .../js/Mailer/MessageEditorController.js | 58 ++++++++++- 7 files changed, 191 insertions(+), 50 deletions(-) diff --git a/UI/Templates/MailerUI/UIxMailPopupView.wox b/UI/Templates/MailerUI/UIxMailPopupView.wox index 1be756ab4..5f45baf84 100644 --- a/UI/Templates/MailerUI/UIxMailPopupView.wox +++ b/UI/Templates/MailerUI/UIxMailPopupView.wox @@ -12,7 +12,7 @@ const:jsFiles="Common.js, Preferences.services.js, Contacts.services.js, Mailer.app.popup.js, Mailer.services.js, vendor/ckeditor/ckeditor.js, vendor/ckeditor/ck.js, vendor/angular-file-upload.min.js">
-
diff --git a/UI/Templates/MailerUI/UIxMailViewTemplate.wox b/UI/Templates/MailerUI/UIxMailViewTemplate.wox index 948b478d1..2e7b63e67 100644 --- a/UI/Templates/MailerUI/UIxMailViewTemplate.wox +++ b/UI/Templates/MailerUI/UIxMailViewTemplate.wox @@ -23,12 +23,11 @@ ng-click="viewer.close()"> arrow_back -
+
-
diff --git a/UI/WebServerResources/js/Mailer/MailboxController.js b/UI/WebServerResources/js/Mailer/MailboxController.js index 941718cac..f89bff85a 100644 --- a/UI/WebServerResources/js/Mailer/MailboxController.js +++ b/UI/WebServerResources/js/Mailer/MailboxController.js @@ -6,10 +6,13 @@ /** * @ngInject */ - MailboxController.$inject = ['$state', '$timeout', '$mdDialog', 'stateAccounts', 'stateAccount', 'stateMailbox', 'encodeUriFilter', 'Dialog', 'Account', 'Mailbox']; - function MailboxController($state, $timeout, $mdDialog, stateAccounts, stateAccount, stateMailbox, encodeUriFilter, Dialog, Account, Mailbox) { + MailboxController.$inject = ['$window', '$state', '$timeout', '$mdDialog', 'stateAccounts', 'stateAccount', 'stateMailbox', 'encodeUriFilter', 'Dialog', 'Account', 'Mailbox']; + function MailboxController($window, $state, $timeout, $mdDialog, stateAccounts, stateAccount, stateMailbox, encodeUriFilter, Dialog, Account, Mailbox) { var vm = this, messageDialog = null; + // Expose controller + $window.$mailboxController = vm; + Mailbox.selectedFolder = stateMailbox; vm.service = Mailbox; diff --git a/UI/WebServerResources/js/Mailer/Mailer.popup.js b/UI/WebServerResources/js/Mailer/Mailer.popup.js index 4b9290414..0857c1e17 100644 --- a/UI/WebServerResources/js/Mailer/Mailer.popup.js +++ b/UI/WebServerResources/js/Mailer/Mailer.popup.js @@ -101,10 +101,18 @@ */ stateAccounts.$inject = ['$q', 'Account']; function stateAccounts($q, Account) { - var promise = Account.$findAll(); - // Fetch list of mailboxes for each account - return promise.then(function(accounts) { - var promises = []; + var accounts, promises = []; + + if (window && + window.opener && + window.opener.$mailboxController) { + // Mail accounts are available from the parent window + accounts = window.opener.$mailboxController.accounts; + return $q.when(accounts); + } + else { + accounts = Account.$findAll(); + // Fetch list of mailboxes for each account angular.forEach(accounts, function(account, i) { var mailboxes = account.$getMailboxes(); promises.push(mailboxes.then(function(objects) { @@ -112,7 +120,7 @@ })); }); return $q.all(promises); - }); + } } /** @@ -160,12 +168,26 @@ /** * @ngInject */ - stateMessage.$inject = ['encodeUriFilter', '$stateParams', '$state', 'stateMailbox', 'Message']; - function stateMessage(encodeUriFilter, $stateParams, $state, stateMailbox, Message) { - var data = { uid: $stateParams.messageId.toString() }, - message = new Message(stateMailbox.$account.id, stateMailbox, data); + stateMessage.$inject = ['encodeUriFilter', '$q', '$stateParams', '$state', 'stateMailbox', 'Message']; + function stateMessage(encodeUriFilter, $q, $stateParams, $state, stateMailbox, Message) { + var data, message; - return message.$reload(); + if (window && + window.opener && + window.opener.$messageController && + window.opener.$messageController.message.uid == parseInt($stateParams.messageId)) { + // Message is available from the parent window + message = new Message(stateMailbox.$account.id, + stateMailbox, + window.opener.$messageController.message.$omit()); + return $q.when(message); + } + else { + // Message is not available; load it from the server + data = { uid: $stateParams.messageId.toString() }; + message = new Message(stateMailbox.$account.id, stateMailbox, data); + return message.$reload(); + } } /** @@ -179,10 +201,14 @@ /** * @ngInject */ - runBlock.$inject = ['$rootScope']; - function runBlock($rootScope) { + runBlock.$inject = ['$window', '$rootScope', '$log']; + function runBlock($window, $rootScope, $log) { + $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { + $log.error(error); + $window.close(); + }); $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) { - console.error(event, current, previous, rejection); + $log.error(event, current, previous, rejection); }); } @@ -207,8 +233,7 @@ } }) .finally(function() { - if ($window.opener) - $window.close(); + $window.close(); }); } diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js index ba340f7fd..96c262996 100644 --- a/UI/WebServerResources/js/Mailer/Message.service.js +++ b/UI/WebServerResources/js/Mailer/Message.service.js @@ -22,13 +22,11 @@ // Data is immediately available if (typeof futureMessageData.then !== 'function') { //console.debug(JSON.stringify(futureMessageData, undefined, 2)); - if (angular.isDefined(lazy) && lazy) { - this.uid = futureMessageData.uid; - } - else { + if (angular.isUndefined(lazy) || !lazy) { angular.extend(this, futureMessageData); this.$formatFullAddresses(); } + this.uid = parseInt(futureMessageData.uid); } else { // The promise will be unwrapped first @@ -132,7 +130,7 @@ var oldUID = (this.uid || -1); if (oldUID != parseInt(uid)) { - this.uid = uid; + this.uid = parseInt(uid); if (oldUID > -1) { oldUID = oldUID.toString(); if (angular.isDefined(this.$mailbox.uidsMap[oldUID])) { @@ -142,7 +140,8 @@ } else { // Refresh selected folder if it's the drafts mailbox - if (this.$mailbox.constructor.selectedFolder.type == 'draft') { + if (this.$mailbox.constructor.selectedFolder && + this.$mailbox.constructor.selectedFolder.type == 'draft') { this.$mailbox.constructor.selectedFolder.$filter(); } } @@ -646,13 +645,6 @@ } }); - // Format addresses as arrays - _.each(['from', 'to', 'cc', 'bcc', 'reply-to'], function(type) { - if (message[type]) - message[type] = _.invoke(message[type].split(','), 'trim'); - }); - - //Message.$log.debug(JSON.stringify(message, undefined, 2)); return message; }; diff --git a/UI/WebServerResources/js/Mailer/MessageController.js b/UI/WebServerResources/js/Mailer/MessageController.js index e9c8b1b8b..b83984a39 100644 --- a/UI/WebServerResources/js/Mailer/MessageController.js +++ b/UI/WebServerResources/js/Mailer/MessageController.js @@ -10,6 +10,10 @@ function MessageController($window, $scope, $state, $mdDialog, stateAccounts, stateAccount, stateMailbox, stateMessage, encodeUriFilter, sgSettings, focus, Dialog, Account, Mailbox, Message) { var vm = this, messageDialog = null, popupWindow = null; + // Expose controller + $window.$messageController = vm; + + vm.$state = $state; vm.accounts = stateAccounts; vm.account = stateAccount; vm.mailbox = stateMailbox; @@ -32,14 +36,54 @@ vm.toggleRawSource = toggleRawSource; vm.showRawSource = false; - // Watch the message model "flags" attribute to remove on-the-fly a tag from the IMAP message - // when removed from the message viewer. - // TODO: this approach should be reviewed once md-chips supports ng-change. - $scope.$watchCollection('viewer.message.flags', function(oldTags, newTags) { - _.each(_.difference(newTags, oldTags), function(tag) { - vm.message.removeTag(tag); + // One-way refresh of the parent window when modifying the message from a popup window. + if ($window.opener) { + // Update the message flags. The message must be displayed in the parent window. + $scope.$watchCollection('viewer.message.flags', function(newTags, oldTags) { + var ctrls; + if (newTags || oldTags) { + ctrls = $parentControllers(); + if (ctrls.messageCtrl) { + ctrls.messageCtrl.service.$timeout(function() { + ctrls.messageCtrl.message.flags = newTags; + }); + } + } }); - }); + // Update the "isflagged" (star icon) of the message. The mailbox must be displayed in the parent window. + $scope.$watch('viewer.message.isflagged', function(isflagged, wasflagged) { + var ctrls = $parentControllers(); + if (ctrls.mailboxCtrl) { + ctrls.mailboxCtrl.service.$timeout(function() { + var message = _.find(ctrls.mailboxCtrl.selectedFolder.$messages, { uid: vm.message.uid }); + message.isflagged = isflagged; + }); + } + }); + } + + /** + * If this is a popup window, retrieve the matching controllers (mailbox and message) of the parent window. + */ + function $parentControllers() { + var message, mailbox, ctrls = {}; + if ($window.opener) { + // Deleting the message from a popup window + if ($window.opener.$mailboxController && + $window.opener.$mailboxController.selectedFolder.$id() == stateMailbox.$id()) { + // The message mailbox is opened in the parent window + mailbox = $window.opener.$mailboxController; + ctrls.mailboxCtrl = mailbox; + if ($window.opener.$messageController && + $window.opener.$messageController.message.uid == stateMessage.uid) { + // The message is opened in the parent window + message = $window.opener.$messageController; + ctrls.messageCtrl = message; + } + } + } + return ctrls; + } function showDetailedRecipients($event) { vm.$showDetailedRecipients = true; @@ -48,16 +92,36 @@ } function doDelete() { - stateMailbox.$deleteMessages([stateMessage]).then(function() { + var parentCtrls = $parentControllers(), mailbox, message, state; + + if (parentCtrls.messageCtrl) { + mailbox = parentCtrls.mailboxCtrl.selectedFolder; + message = parentCtrls.messageCtrl.message; + state = parentCtrls.messageCtrl.$state; + } + else { + mailbox = stateMailbox; + message = stateMessage; + state = $state; + } + + mailbox.$deleteMessages([message]).then(function() { // Remove message from list of messages - var index = _.findIndex(stateMailbox.$messages, function(o) { - return o.uid == stateMessage.uid; + var index = _.findIndex(mailbox.$messages, function(o) { + return o.uid == message.uid; }); if (index != -1) - stateMailbox.$messages.splice(index, 1); + mailbox.$messages.splice(index, 1); // Remove message object from scope - vm.message = null; - $state.go('mail.account.mailbox', { accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path) }); + message = null; + // Navigate to mailbox if not in popup window + if (angular.isDefined(state)) { + try { + state.go('mail.account.mailbox', { mailboxId: encodeUriFilter(mailbox.path) }); + } + catch (error) {} + } + closePopup(); }); } @@ -77,18 +141,20 @@ controllerAs: 'editor', locals: { stateAccounts: vm.accounts, + stateAccount: vm.account, stateMessage: message, stateRecipients: recipients } }) .finally(function() { messageDialog = null; + closePopup(); }); } } function close() { - $state.go('mail.account.mailbox', { accountId: stateAccount.id, mailboxId: encodeUriFilter(stateMailbox.path) }).then(function() { + $state.go('mail.account.mailbox').then(function() { vm.message = null; delete stateMailbox.selectedMessage; }); @@ -139,7 +205,8 @@ } function closePopup() { - $window.close(); + if ($window.opener) + $window.close(); } function newMessage($event, recipient) { diff --git a/UI/WebServerResources/js/Mailer/MessageEditorController.js b/UI/WebServerResources/js/Mailer/MessageEditorController.js index 41853c2c2..321c346b7 100644 --- a/UI/WebServerResources/js/Mailer/MessageEditorController.js +++ b/UI/WebServerResources/js/Mailer/MessageEditorController.js @@ -6,8 +6,8 @@ /** * @ngInject */ - MessageEditorController.$inject = ['$stateParams', '$mdConstant', '$mdDialog', '$mdToast', 'FileUploader', 'stateAccounts', 'stateMessage', 'stateRecipients', '$timeout', 'Dialog', 'AddressBook', 'Card', 'Preferences']; - function MessageEditorController($stateParams, $mdConstant, $mdDialog, $mdToast, FileUploader, stateAccounts, stateMessage, stateRecipients, $timeout, Dialog, AddressBook, Card, Preferences) { + MessageEditorController.$inject = ['$window', '$stateParams', '$mdConstant', '$mdDialog', '$mdToast', 'FileUploader', 'stateAccounts', 'stateAccount', 'stateMessage', 'stateRecipients', 'encodeUriFilter', '$timeout', 'Dialog', 'AddressBook', 'Card', 'Preferences']; + function MessageEditorController($window, $stateParams, $mdConstant, $mdDialog, $mdToast, FileUploader, stateAccounts, stateAccount, stateMessage, stateRecipients, encodeUriFilter, $timeout, Dialog, AddressBook, Card, Preferences) { var vm = this, semicolon = 186; vm.addRecipient = addRecipient; @@ -77,6 +77,33 @@ vm.message.editable.to = _.union(vm.message.editable.to, _.pluck(stateRecipients, 'full')); } + /** + * If this is a popup window, retrieve the mailbox controller of the parent window. + */ + function $parentControllers() { + var originMessage, ctrls = {}; + if ($window.opener) { + if ($window.opener.$mailboxController) { + if ($window.opener.$mailboxController.selectedFolder.type == 'draft') { + ctrls.draftMailboxCtrl = $window.opener.$mailboxController; + if ($window.opener.$messageController && + $window.opener.$messageController.message.uid == stateMessage.uid) { + // The draft is opened in the parent window + ctrls.draftMessageCtrl = $window.opener.$messageController; + } + } + else if (stateMessage.origin) { + originMessage = stateMessage.origin.message; + if ($window.opener.$mailboxController.selectedFolder.$id() == originMessage.$mailbox.$id()) { + // The message mailbox is opened in the parent window + ctrls.originMailboxCtrl = $window.opener.$mailboxController; + } + } + } + } + return ctrls; + } + function addAttachments() { // Add existing attached files to uploader var i, data, fileItem; @@ -114,7 +141,18 @@ } function save() { + var ctrls = $parentControllers(); vm.message.$save().then(function(data) { + if (ctrls.draftMailboxCtrl) { + // We're saving a draft from a popup window. + // Reload draft mailbox + ctrls.draftMailboxCtrl.selectedFolder.$filter().then(function() { + if (ctrls.draftMessageCtrl) { + // Reload selected message + ctrls.draftMessageCtrl.$state.go('mail.account.mailbox.message', { messageId: vm.message.uid }); + } + }); + } $mdToast.show( $mdToast.simple() .content(l('Your email has been saved')) @@ -124,10 +162,26 @@ } function send() { + var ctrls = $parentControllers(); if (vm.autosave) $timeout.cancel(vm.autosave); vm.message.$send().then(function(data) { + if (ctrls.draftMailboxCtrl) { + // We're sending a draft from a popup window and the draft mailbox is opened. + // Reload draft mailbox + ctrls.draftMailboxCtrl.selectedFolder.$filter().then(function() { + if (ctrls.draftMessageCtrl) { + // Close draft + ctrls.draftMessageCtrl.close(); + } + }); + } + if (ctrls.originMailboxCtrl) { + // We're sending a draft from a popup window and the original mailbox is opened. + // Reload mailbox + ctrls.originMailboxCtrl.selectedFolder.$filter(); + } $mdToast.show( $mdToast.simple() .content(l('Your email has been sent'))