1
0
mirror of https://github.com/moparisthebest/mail synced 2025-02-19 20:31:48 -05:00

Merge pull request #5 from whiteout-io/dev/editor

Dev/editor
This commit is contained in:
Tankred Hase 2014-01-19 12:05:13 -08:00
commit 7ec662e682
5 changed files with 114 additions and 68 deletions

View File

@ -6,15 +6,19 @@ define(function(require) {
aes = require('cryptoLib/aes-cbc'), aes = require('cryptoLib/aes-cbc'),
util = require('cryptoLib/util'), util = require('cryptoLib/util'),
str = require('js/app-config').string, str = require('js/app-config').string,
emailDao; crypto, emailDao;
// //
// Controller // Controller
// //
var WriteCtrl = function($scope, $filter) { var WriteCtrl = function($scope, $filter) {
crypto = appController._crypto;
emailDao = appController._emailDao; emailDao = appController._emailDao;
// set default value so that the popover height is correct on init
$scope.fingerprint = 'XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX';
// //
// Init // Init
// //
@ -88,19 +92,7 @@ define(function(require) {
* This event is fired when editing the email address headers. It checks is space is pressed and if so, creates a new address field. * This event is fired when editing the email address headers. It checks is space is pressed and if so, creates a new address field.
*/ */
$scope.onAddressUpdate = function(field, index) { $scope.onAddressUpdate = function(field, index) {
var recipient = field[index], var recipient = field[index];
address = recipient.address;
// handle number of email inputs for multiple recipients
if (address.indexOf(' ') !== -1) {
recipient.address = address.replace(' ', '');
field.push({
address: ''
});
} else if (address.length === 0 && field.length > 1) {
field.splice(field.indexOf(recipient), 1);
}
$scope.verify(recipient); $scope.verify(recipient);
}; };
@ -137,6 +129,20 @@ define(function(require) {
}); });
}; };
$scope.getFingerprint = function(recipient) {
$scope.fingerprint = 'Fingerprint cannot be displayed. Public key not found for that user.';
if (!recipient.key) {
return;
}
var fpr = crypto.getFingerprint(recipient.key.publicKey);
var formatted = fpr.slice(0, 4) + ' ' + fpr.slice(4, 8) + ' ' + fpr.slice(8, 12) + ' ' + fpr.slice(12, 16) + ' ' + fpr.slice(16, 20) + ' ' + fpr.slice(20, 24) + ' ' + fpr.slice(24, 28) + ' ' + fpr.slice(28, 32) + ' ' + fpr.slice(32, 36) + ' ' + fpr.slice(36);
$scope.fingerprint = formatted;
$scope.$apply();
};
/** /**
* Check if it is ok to send an email depending on the invitation state of the addresses * Check if it is ok to send an email depending on the invitation state of the addresses
*/ */
@ -319,9 +325,9 @@ define(function(require) {
return { return {
//scope: true, // optionally create a child scope //scope: true, // optionally create a child scope
link: function(scope, element) { link: function(scope, element) {
element[0].onclick = function() { element.on('click', function() {
element[0].children[0].focus(); element[0].children[0].focus();
}; });
} }
}; };
}); });
@ -330,6 +336,7 @@ define(function(require) {
return { return {
require: 'ngModel', require: 'ngModel',
link: function(scope, elm, attrs) { link: function(scope, elm, attrs) {
// resize text input depending on value length
var model = $parse(attrs.autoSize); var model = $parse(attrs.autoSize);
scope.$watch(model, function(value) { scope.$watch(model, function(value) {
var width; var width;
@ -346,21 +353,88 @@ define(function(require) {
}; };
}); });
ngModule.directive('addressInput', function($timeout) { function addInput(field, scope) {
field.push({
address: ''
});
scope.$apply();
}
function checkForEmptyInput(field) {
var emptyFieldExists = false;
field.forEach(function(recipient) {
if (!recipient.address) {
emptyFieldExists = true;
}
});
return emptyFieldExists;
}
ngModule.directive('field', function() {
return {
//scope: true, // optionally create a child scope
link: function(scope, element, attrs) {
element.on('click', function() {
var fieldName = attrs.field;
var field = scope[fieldName];
if (!checkForEmptyInput(field)) {
// create new field input if no empy one exists
addInput(field, scope);
}
// focus on last input when clicking on field
var id = fieldName + (field.length - 1);
document.getElementById(id).focus();
});
}
};
});
ngModule.directive('addressInput', function() {
return { return {
//scope: true, // optionally create a child scope //scope: true, // optionally create a child scope
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
// get prefix for id // get prefix for id
var idPrefix = attrs.addressInput; var fieldName = attrs.addressInput;
element.bind('keydown', function(e) { var field = scope[fieldName];
if (e.keyCode === 32) { var index = parseInt(attrs.id.replace(fieldName, ''), 10);
// space -> go to next input
$timeout(function() { element.on('click', function(e) {
// focus on this one and dont bubble to field click handler
e.stopPropagation();
});
element.on('blur', function() {
if (!checkForEmptyInput(field)) {
// create new field input
addInput(field, scope);
}
});
element.on('keydown', function(e) {
var code = e.keyCode;
if (code === 32 || code === 188 || code === 186) {
// catch space, comma, semicolon
e.preventDefault();
// create new field input
addInput(field, scope);
// find next input and focus // find next input and focus
var index = attrs.id.replace(idPrefix, ''); var nextId = fieldName + (index + 1);
var nextId = idPrefix + (parseInt(index, 10) + 1);
document.getElementById(nextId).focus(); document.getElementById(nextId).focus();
}, 100);
} else if ((code === 8 || code === 46) && !field[index].address && field.length > 1) {
// backspace, delete on empty input
// remove input
e.preventDefault();
field.splice(index, 1);
scope.$apply();
// focus on previous id
var previousId = fieldName + (index - 1);
document.getElementById(previousId).focus();
} }
}); });
} }

View File

@ -7,7 +7,7 @@
top: -9999px; top: -9999px;
left: -9999px; left: -9999px;
display: block; display: block;
z-index: 1010; z-index: 9000;
max-width: 276px; max-width: 276px;
padding: 1px; padding: 1px;
text-align: left; text-align: left;

View File

@ -24,6 +24,7 @@
p { p {
margin: 0.2em 0; margin: 0.2em 0;
padding: 0.2em 0; padding: 0.2em 0;
cursor: text;
} }
span { span {

View File

@ -7,16 +7,16 @@
<div class="view-write"> <div class="view-write">
<div class="headers"> <div class="headers">
<p> <p field="to">
<span>To:</span> <span>To:</span>
<span ng-repeat="recipient in to track by $index"> <span ng-repeat="recipient in to track by $index">
<input id="to{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(to, $index)" address-input="to" tabindex="1" focus-me="state.writer.open && writerTitle !== 'Reply'"> <input id="to{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(to, $index)" address-input="to" tabindex="1" ng-mouseover="getFingerprint(recipient)" popover="#fingerprint-writer" focus-me="state.writer.open && writerTitle !== 'Reply'">
</span> </span>
</p> </p>
<p> <p field="cc">
<span>Cc:</span> <span>Cc:</span>
<span ng-repeat="recipient in cc track by $index"> <span ng-repeat="recipient in cc track by $index">
<input id="cc{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(cc, $index)" address-input="cc" tabindex="1"> <input id="cc{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(cc, $index)" address-input="cc" tabindex="1" ng-mouseover="getFingerprint(recipient)" popover="#fingerprint-writer">
</span> </span>
</p> </p>
</div><!--/.address-headers--> </div><!--/.address-headers-->
@ -44,4 +44,11 @@
</div><!--/.write-view--> </div><!--/.write-view-->
</div><!--/.content--> </div><!--/.content-->
<!-- popovers -->
<div id="fingerprint-writer" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>PGP Fingerprint</b></div>
<div class="popover-content">{{fingerprint}}</div>
</div><!--/.popover-->
</div><!--/.lightbox-body--> </div><!--/.lightbox-body-->

View File

@ -126,42 +126,6 @@ define(function(require) {
scope.verify.restore(); scope.verify.restore();
}); });
it('should add new field item if space is pressed', function() {
var to = [{
address: 'asdf@asdf.de '
}];
scope.onAddressUpdate(to, 0);
expect(to.length).to.equal(2);
expect(to[0].address).to.equal('asdf@asdf.de');
expect(to[1].address).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
});
it('should remove field item if address is empty', function() {
var to = [{
address: 'asdf@asdf.de'
}, {
address: ''
}];
scope.onAddressUpdate(to, 1);
expect(to.length).to.equal(1);
expect(to[0].address).to.equal('asdf@asdf.de');
expect(verifyMock.calledOnce).to.be.true;
});
it('should not remove last field item if address is empty', function() {
var to = [{
address: ''
}];
scope.onAddressUpdate(to, 0);
expect(to.length).to.equal(1);
expect(to[0].address).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
});
it('should do nothing for normal address', function() { it('should do nothing for normal address', function() {
var to = [{ var to = [{
address: 'asdf@asdf.de' address: 'asdf@asdf.de'