From 5e5e52e3f15f022d37b150abe85cc8dd4c1d44eb Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 29 Aug 2017 11:45:24 -0400 Subject: [PATCH] register web app as a handler for mailto scheme Fixes #1223 --- NEWS | 1 + UI/Templates/MailerUI/UIxMailEditor.wox | 3 +- .../js/Mailer/Account.service.js | 4 +- UI/WebServerResources/js/Mailer/Mailer.app.js | 10 ++- .../js/Mailer/Mailer.popup.js | 66 +++++++++++++------ .../js/Mailer/Message.service.js | 35 ++++++++++ .../js/Mailer/MessageController.js | 32 ++------- 7 files changed, 99 insertions(+), 52 deletions(-) diff --git a/NEWS b/NEWS index 2e5fb15937..549ee37548 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ New features - [core] can now invite attendees to exceptions only (#2561) - [web] display freebusy information of owner in appointment editor + - [web] register SOGo as a handler for the mailto scheme (#1223) Enhancements - diff --git a/UI/Templates/MailerUI/UIxMailEditor.wox b/UI/Templates/MailerUI/UIxMailEditor.wox index cd3955947c..92737a241f 100644 --- a/UI/Templates/MailerUI/UIxMailEditor.wox +++ b/UI/Templates/MailerUI/UIxMailEditor.wox @@ -12,8 +12,7 @@ nv-file-drop="nv-file-drop" nv-file-over="nv-file-over" over-class="sg-over-dropzone" - uploader="editor.uploader" - ng-controller="navController"> + uploader="editor.uploader">
diff --git a/UI/WebServerResources/js/Mailer/Account.service.js b/UI/WebServerResources/js/Mailer/Account.service.js index 340c6fb0e9..4c79ed37db 100644 --- a/UI/WebServerResources/js/Mailer/Account.service.js +++ b/UI/WebServerResources/js/Mailer/Account.service.js @@ -300,7 +300,7 @@ * @desc Prepare a new Message object associated to the appropriate mailbox. * @returns a promise of the HTTP operations */ - Account.prototype.$newMessage = function() { + Account.prototype.$newMessage = function(options) { var _this = this; // Query account for draft folder and draft UID @@ -314,6 +314,8 @@ Account.$log.debug('New message (edit): ' + JSON.stringify(data, undefined, 2)); angular.extend(message.editable, data); message.isNew = true; + if (options && options.mailto) + message.$parseMailto(options.mailto); return message; }); }); diff --git a/UI/WebServerResources/js/Mailer/Mailer.app.js b/UI/WebServerResources/js/Mailer/Mailer.app.js index 15abaec515..efed1cb6d3 100644 --- a/UI/WebServerResources/js/Mailer/Mailer.app.js +++ b/UI/WebServerResources/js/Mailer/Mailer.app.js @@ -141,6 +141,12 @@ // if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/Mail/0/inbox'); + + // Try to register SOGo has an handler for mailto: links + if (navigator && navigator.registerProtocolHandler) { + var mailtoURL = window.location.origin + window.ApplicationBaseURL + 'UIxMailPopupView#!/Mail/0/INBOX/new?%s'; + navigator.registerProtocolHandler('mailto', mailtoURL, 'SOGo'); + } } /** @@ -178,8 +184,8 @@ /** * @ngInject */ - stateMailbox.$inject = ['$q', '$state', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox']; - function stateMailbox($q, $state, $stateParams, stateAccount, decodeUriFilter, Mailbox) { + stateMailbox.$inject = ['$q', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox']; + function stateMailbox($q, $stateParams, stateAccount, decodeUriFilter, Mailbox) { var mailbox, mailboxId = decodeUriFilter($stateParams.mailboxId), _find; diff --git a/UI/WebServerResources/js/Mailer/Mailer.popup.js b/UI/WebServerResources/js/Mailer/Mailer.popup.js index 19c4f4a3c5..a5bd9541a9 100644 --- a/UI/WebServerResources/js/Mailer/Mailer.popup.js +++ b/UI/WebServerResources/js/Mailer/Mailer.popup.js @@ -99,27 +99,33 @@ /** * @ngInject */ - stateAccounts.$inject = ['$q', 'Account']; - function stateAccounts($q, Account) { + stateAccounts.$inject = ['$window', '$q', 'Account']; + function stateAccounts($window, $q, Account) { var accounts, promises = []; - if (window && - window.opener && - window.opener.$mailboxController) { + if ($window && + $window.opener && + $window.opener.$mailboxController) { // Mail accounts are available from the parent window - accounts = window.opener.$mailboxController.accounts; + 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) { - return account; - })); + return Account.$findAll().then(function(accounts) { + // Fetch list of mailboxes for each account + angular.forEach(accounts, function(account, i) { + var mailboxes = account.$getMailboxes(); + if (i === 0) + // Make sure we have the list of mailboxes of the first account + promises.push(mailboxes.then(function(objects) { + return account; + })); + else + // Don't wait for external accounts + promises.push(account); + }); + return $q.all(promises); }); - return $q.all(promises); } } @@ -136,10 +142,12 @@ /** * @ngInject */ - stateMailbox.$inject = ['$stateParams', 'stateAccount', 'decodeUriFilter']; - function stateMailbox($stateParams, stateAccount, decodeUriFilter) { - var mailboxId = decodeUriFilter($stateParams.mailboxId), + stateMailbox.$inject = ['$q', '$state', '$stateParams', 'stateAccount', 'decodeUriFilter', 'Mailbox']; + function stateMailbox($q, $state, $stateParams, stateAccount, decodeUriFilter, Mailbox) { + var mailbox, + mailboxId = decodeUriFilter($stateParams.mailboxId), _find; + // Recursive find function _find = function(mailboxes) { var mailbox = _.find(mailboxes, function(o) { @@ -154,15 +162,31 @@ } return mailbox; }; - return _find(stateAccount.$mailboxes); + + mailbox = _find(stateAccount.$mailboxes); + + if (mailbox) { + mailbox.$topIndex = 0; + mailbox.selectFolder(); + return mailbox; + } + else + // Mailbox not found + return $q.reject("Mailbox doesn't exist"); } /** * @ngInject */ - stateNewMessage.$inject = ['stateAccount']; - function stateNewMessage(stateAccount) { - return stateAccount.$newMessage(); + stateNewMessage.$inject = ['$urlService', 'stateAccount']; + function stateNewMessage($urlService, stateAccount) { + var mailto, params = $urlService.search(); + if (params) { + mailto = _.find(_.keys(params), function(k) { + return /^mailto:/i.test(k); + }); + } + return stateAccount.$newMessage({ mailto: mailto }); } /** diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js index 0a412ffab0..c57777f461 100644 --- a/UI/WebServerResources/js/Mailer/Message.service.js +++ b/UI/WebServerResources/js/Mailer/Message.service.js @@ -544,6 +544,41 @@ return this.$unwrap(futureMessageData); }; + /** + * @function $parseMailto + * @memberof Message.prototype + * @desc Extend the editable content of the message with the + * information parsed from the specified "mailto:" link. + */ + Message.prototype.$parseMailto = function(mailto) { + var to, data, match = /^mailto:([^\?]+)/.exec(mailto); + if (match) { + // Recipients + to = _.map(decodeURIComponent(match[1]).split(','), function(email) { + return '<' + email.trim() + '>'; + }); + data = { to: to }; + // Subject & body + _.forEach(['subject', 'body'], function(param) { + var re = new RegExp(param + '=([^&]+)'); + param = (param == 'body')? 'text' : param; + match = re.exec(mailto); + if (match) + data[param] = decodeURIComponent(match[1]); + }); + // Other Recipients + _.forEach(['cc', 'bcc'], function(param) { + var re = new RegExp(param + '=([^&]+)'); + match = re.exec(mailto); + if (match) + data[param] = _.map(decodeURIComponent(match[1]).split(','), function(email) { + return '<' + email.trim() + '>'; + }); + }); + angular.extend(this.editable, data); + } + }; + /** * @function $reply * @memberof Message.prototype diff --git a/UI/WebServerResources/js/Mailer/MessageController.js b/UI/WebServerResources/js/Mailer/MessageController.js index a4db1a9520..7ef67368fd 100644 --- a/UI/WebServerResources/js/Mailer/MessageController.js +++ b/UI/WebServerResources/js/Mailer/MessageController.js @@ -193,27 +193,8 @@ href = $event.target.attributes.href.value; match = /^mailto:([^\?]+)/.exec(href); if (match) { - // Recipients - to = _.map(decodeURIComponent(match[1]).split(','), function(email) { - return '<' + email + '>'; - }); - data = { to: to }; - // Subject & body - _.forEach(['subject', 'body'], function(param) { - var re = new RegExp(param + '=([^&]+)'); - param = (param == 'body')? 'text' : param; - match = re.exec(href); - if (match) - data[param] = [decodeURIComponent(match[1])]; - }); - // Recipients - _.forEach(['cc', 'bcc'], function(param) { - var re = new RegExp(param + '=([^&]+)'); - match = re.exec(href); - if (match) - data[param] = [decodeURIComponent(match[1])]; - }); - this.newMessage($event, data); // will stop event propagation + delete $event.target.attributes.target; + this.newMessage($event, href); // will stop event propagation } } }; @@ -359,13 +340,12 @@ $window.close(); }; - this.newMessage = function($event, editableContent) { - this.account.$newMessage().then(function(message) { - angular.extend(message.editable, editableContent); - _showMailEditor($event, message); - }); + this.newMessage = function($event, mailto) { $event.stopPropagation(); $event.preventDefault(); + this.account.$newMessage({ mailto: mailto }).then(function(message) { + _showMailEditor($event, message); + }); }; this.toggleRawSource = function($event) {