mirror of
https://github.com/moparisthebest/mail
synced 2024-11-29 20:32:15 -05:00
Merge pull request #43 from whiteout-io/dev/reply-all
[WO-281] implement reply all and forward
This commit is contained in:
commit
a33e9ff3dc
@ -87,7 +87,7 @@ define(function(require) {
|
||||
};
|
||||
|
||||
self.onConnect = function(callback) {
|
||||
if (!self.isOnline() || !self._emailDao._account) {
|
||||
if (!self.isOnline() || !self._emailDao || !self._emailDao._account) {
|
||||
// prevent connection infinite loop
|
||||
callback();
|
||||
return;
|
||||
|
@ -285,6 +285,9 @@ define(function(require) {
|
||||
this.to = [{
|
||||
address: 'max.musterman@gmail.com'
|
||||
}]; // list of receivers
|
||||
this.cc = [{
|
||||
address: 'john.doe@gmail.com'
|
||||
}]; // list of receivers
|
||||
if (attachments) {
|
||||
// body structure with three attachments
|
||||
this.bodystructure = {
|
||||
|
@ -164,6 +164,45 @@ define(function(require) {
|
||||
|
||||
var ngModule = angular.module('read', []);
|
||||
|
||||
ngModule.directive('replySelection', function() {
|
||||
return function(scope, elm) {
|
||||
var popover = angular.element(document.querySelector('.reply-selection')),
|
||||
visible = false;
|
||||
|
||||
elm.on('touchstart click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
visible = true;
|
||||
|
||||
// set popover position
|
||||
var top = elm[0].offsetTop;
|
||||
var left = elm[0].offsetLeft;
|
||||
var width = elm[0].offsetWidth;
|
||||
var height = elm[0].offsetHeight;
|
||||
|
||||
popover[0].style.transition = 'opacity 0.1s linear';
|
||||
popover[0].style.top = (top + height) + 'px';
|
||||
popover[0].style.left = (left + width / 2 - popover[0].offsetWidth / 2) + 'px';
|
||||
popover[0].style.opacity = '1';
|
||||
});
|
||||
|
||||
elm.parent().parent().on('touchstart click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
popover[0].style.transition = 'opacity 0.25s linear, top 0.25s step-end, left 0.25s step-end';
|
||||
popover[0].style.opacity = '0';
|
||||
popover[0].style.top = '-9999px';
|
||||
popover[0].style.left = '-9999px';
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
ngModule.directive('frameLoad', function() {
|
||||
return function(scope, elm) {
|
||||
elm.bind('load', function() {
|
||||
|
@ -26,14 +26,14 @@ define(function(require) {
|
||||
|
||||
$scope.state.writer = {
|
||||
open: false,
|
||||
write: function(replyTo) {
|
||||
write: function(replyTo, replyAll, forward) {
|
||||
this.open = true;
|
||||
$scope.replyTo = replyTo;
|
||||
|
||||
resetFields();
|
||||
|
||||
// fill fields depending on replyTo
|
||||
fillFields(replyTo);
|
||||
fillFields(replyTo, replyAll, forward);
|
||||
$scope.updatePreview();
|
||||
|
||||
$scope.verify($scope.to[0]);
|
||||
@ -60,24 +60,67 @@ define(function(require) {
|
||||
$scope.attachments = [];
|
||||
}
|
||||
|
||||
function fillFields(re) {
|
||||
var from, body;
|
||||
function fillFields(re, replyAll, forward) {
|
||||
var from, sentDate, body;
|
||||
|
||||
if (!re) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.writerTitle = 'Reply';
|
||||
$scope.writerTitle = (forward) ? 'Forward' : 'Reply';
|
||||
|
||||
// fill recipient field
|
||||
if (!forward) {
|
||||
$scope.to.unshift({
|
||||
address: re.from[0].address
|
||||
});
|
||||
$scope.to.forEach($scope.verify);
|
||||
}
|
||||
if (replyAll) {
|
||||
re.to.concat(re.cc).forEach(function(recipient) {
|
||||
if (recipient.address === emailDao._account.emailAddress) {
|
||||
// don't reply to yourself
|
||||
return;
|
||||
}
|
||||
$scope.cc.unshift({
|
||||
address: recipient.address
|
||||
});
|
||||
});
|
||||
$scope.cc.forEach($scope.verify);
|
||||
}
|
||||
|
||||
// fill subject
|
||||
if (forward) {
|
||||
$scope.subject = 'Fwd: ' + re.subject;
|
||||
} else {
|
||||
$scope.subject = 'Re: ' + ((re.subject) ? re.subject.replace('Re: ', '') : '');
|
||||
}
|
||||
|
||||
// fill text body
|
||||
from = re.from[0].name || re.from[0].address;
|
||||
body = '\n\n' + $filter('date')(re.sentDate, 'EEEE, MMM d, yyyy h:mm a') + ' ' + from + ' wrote:\n> ';
|
||||
sentDate = $filter('date')(re.sentDate, 'EEEE, MMM d, yyyy h:mm a');
|
||||
|
||||
function createString(array) {
|
||||
var str = '';
|
||||
array.forEach(function(to) {
|
||||
str += (str) ? ', ' : '';
|
||||
str += ((to.name) ? to.name : to.address) + ' <' + to.address + '>';
|
||||
});
|
||||
return str;
|
||||
}
|
||||
|
||||
if (forward) {
|
||||
body = '\n\n' +
|
||||
'---------- Forwarded message ----------\n' +
|
||||
'From: ' + re.from[0].name + ' <' + re.from[0].address + '>\n' +
|
||||
'Date: ' + sentDate + '\n' +
|
||||
'Subject: ' + re.subject + '\n' +
|
||||
'To: ' + createString(re.to) + '\n' +
|
||||
'Cc: ' + createString(re.cc) + '\n\n\n';
|
||||
|
||||
} else {
|
||||
body = '\n\n' + sentDate + ' ' + from + ' wrote:\n> ';
|
||||
}
|
||||
|
||||
// only display non html mails in reply part
|
||||
if (!re.html) {
|
||||
|
@ -44,7 +44,7 @@ textarea {
|
||||
height: 100%;
|
||||
|
||||
// allow text selection
|
||||
-webkit-user-select: text;
|
||||
user-select: none;
|
||||
|
||||
// make scrollbars invisible
|
||||
::-webkit-scrollbar {
|
||||
|
@ -13,10 +13,7 @@
|
||||
text-align: left;
|
||||
background-color: #ffffff;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #cccccc;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid $color-grey-lighter;
|
||||
white-space: normal;
|
||||
opacity: 0;
|
||||
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($color-white, 3%);
|
||||
background-color: darken($color-white, 2%);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
@ -84,6 +84,7 @@
|
||||
line-height: 1.5em;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
user-select: text;
|
||||
|
||||
.working {
|
||||
margin: 0 auto;
|
||||
@ -138,6 +139,24 @@
|
||||
iframe {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.reply-selection {
|
||||
.popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 7px 30px;
|
||||
color: $color-blue;
|
||||
user-select: none;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($color-white, 2%);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="controls">
|
||||
<button ng-click="state.mailList.remove(state.mailList.selected)" class="btn-icon" title="Delete mail"></button>
|
||||
<button ng-click="state.writer.write(state.mailList.selected)" class="btn-icon" title="Reply to"></button>
|
||||
<button class="btn-icon" title="Reply to" reply-selection></button>
|
||||
<button ng-click="state.writer.write()" class="btn-icon" title="New mail"></button>
|
||||
</div><!--/.controls-->
|
||||
|
||||
@ -59,4 +59,15 @@
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">{{keyId}}</div>
|
||||
</div><!--/.popover-->
|
||||
|
||||
<div class="reply-selection popover bottom">
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="option" ng-click="state.writer.write(state.mailList.selected)">Reply</div>
|
||||
<div class="seperator-line"></div>
|
||||
<div class="option" ng-click="state.writer.write(state.mailList.selected, true)">Reply All</div>
|
||||
<div class="seperator-line"></div>
|
||||
<div class="option" ng-click="state.writer.write(state.mailList.selected, null, true)">Forward</div>
|
||||
</div>
|
||||
</div><!--/.reply-selection-->
|
||||
</div><!--/.view-read-->
|
||||
|
@ -10,16 +10,15 @@ define(function(require) {
|
||||
appController = require('js/app-controller');
|
||||
|
||||
describe('Navigation Controller unit test', function() {
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, hasIdentity, outboxFolder;
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, hasIdentity, outboxFolder, onConnectStub;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function(done) {
|
||||
hasIdentity = !! window.chrome.identity;
|
||||
if (!hasIdentity) {
|
||||
window.chrome.identity = {};
|
||||
}
|
||||
// remember original module to restore later
|
||||
origEmailDao = appController._emailDao;
|
||||
|
||||
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||
emailDaoMock._account = {
|
||||
folders: [{
|
||||
@ -37,6 +36,8 @@ define(function(require) {
|
||||
outboxBoMock = sinon.createStubInstance(OutboxBO);
|
||||
appController._outboxBo = outboxBoMock;
|
||||
outboxBoMock.startChecking.returns();
|
||||
onConnectStub = sinon.stub(appController, 'onConnect');
|
||||
onConnectStub.yields();
|
||||
|
||||
angular.module('navigationtest', []);
|
||||
mocks.module('navigationtest');
|
||||
@ -46,6 +47,7 @@ define(function(require) {
|
||||
ctrl = $controller(NavigationCtrl, {
|
||||
$scope: scope
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@ -55,6 +57,7 @@ define(function(require) {
|
||||
if (hasIdentity) {
|
||||
delete window.chrome.identity;
|
||||
}
|
||||
onConnectStub.restore();
|
||||
});
|
||||
|
||||
describe('initial state', function() {
|
||||
|
@ -119,7 +119,7 @@ define(function(require) {
|
||||
expect(scope.subject).to.equal('Re: ' + subject);
|
||||
expect(scope.body).to.contain(body);
|
||||
expect(scope.ciphertextPreview).to.not.be.empty;
|
||||
expect(verifyMock.calledOnce).to.be.true;
|
||||
expect(verifyMock.called).to.be.true;
|
||||
|
||||
scope.verify.restore();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user