mirror of
https://github.com/moparisthebest/mail
synced 2024-11-26 19:02:20 -05:00
Merge pull request #54 from whiteout-io/dev/css
[WO-198] Style message replies with different colors
This commit is contained in:
commit
cae6197e4d
@ -62,7 +62,10 @@ requirejs([
|
|||||||
'contacts',
|
'contacts',
|
||||||
'login-new-device',
|
'login-new-device',
|
||||||
'popover'
|
'popover'
|
||||||
]);
|
], function($rootScopeProvider) {
|
||||||
|
// increase digest iteration limit for large recursive ng-includes in reader
|
||||||
|
$rootScopeProvider.digestTtl(100);
|
||||||
|
});
|
||||||
|
|
||||||
// set router paths
|
// set router paths
|
||||||
app.config(function($routeProvider) {
|
app.config(function($routeProvider) {
|
||||||
|
@ -385,7 +385,17 @@ define(function(require) {
|
|||||||
this.html = html;
|
this.html = html;
|
||||||
this.sentDate = new Date('Thu Sep 19 2013 20:41:23 GMT+0200 (CEST)');
|
this.sentDate = new Date('Thu Sep 19 2013 20:41:23 GMT+0200 (CEST)');
|
||||||
this.subject = 'Getting started'; // Subject line
|
this.subject = 'Getting started'; // Subject line
|
||||||
this.body = 'Here are a few pointers to help you get started with Whiteout Mail.\n\nhttp://www.example.com\n\n# Write encrypted message\n- You can compose a message by clicking on the compose button on the upper right (keyboard shortcut is "n" for a new message or "r" to reply).\n- When typing the recipient\'s email address, secure recipients are marked with a blue label and insecure recipients are red.\n- When sending an email to insecure recipients, the default behavior for Whiteout Mail is to invite them to the service and only send the message content in an encrypted form, once they have joined.\n\n# Advanced features\n- To verify a recipient\'s PGP key, you can hover over the blue label containing their email address and their key fingerprint will be displayed.\n- To view your own key fingerprint, open the account view in the navigation bar on the left. You can compare these with your correspondants over a second channel such as a phonecall.\n\nWe hope this helped you to get started with Whiteout Mail.\n\nYour Whiteout Networks team'; // plaintext body
|
this.body = 'And a good day to you too sir. \n' +
|
||||||
|
'\n' +
|
||||||
|
'Thursday, Apr 24, 2014 3:33 PM safewithme.testuser@gmail.com wrote:\n' +
|
||||||
|
'> adsfadfasdfasdfasfdasdfasdfas\n' +
|
||||||
|
'\n' +
|
||||||
|
'http://example.com\n' +
|
||||||
|
'\n' +
|
||||||
|
'> Tuesday, Mar 25, 2014 4:19 PM gianniarcore@gmail.com wrote:\n' +
|
||||||
|
'>> from 0.7.0.1\n' +
|
||||||
|
'>>\n' +
|
||||||
|
'>> God speed!'; // plaintext body
|
||||||
this.encrypted = true;
|
this.encrypted = true;
|
||||||
this.decrypted = true;
|
this.decrypted = true;
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,7 @@ define(function(require) {
|
|||||||
// Controller
|
// Controller
|
||||||
//
|
//
|
||||||
|
|
||||||
var ReadCtrl = function($scope) {
|
var ReadCtrl = function($scope, $timeout) {
|
||||||
|
|
||||||
emailDao = appController._emailDao;
|
emailDao = appController._emailDao;
|
||||||
invitationDao = appController._invitationDao;
|
invitationDao = appController._invitationDao;
|
||||||
@ -66,6 +66,21 @@ define(function(require) {
|
|||||||
mail.to.forEach(checkPublicKey);
|
mail.to.forEach(checkPublicKey);
|
||||||
// display recipient security status
|
// display recipient security status
|
||||||
Array.isArray(mail.cc) && mail.cc.forEach(checkPublicKey);
|
Array.isArray(mail.cc) && mail.cc.forEach(checkPublicKey);
|
||||||
|
|
||||||
|
$scope.node = undefined;
|
||||||
|
});
|
||||||
|
$scope.$watch('state.mailList.selected.body', function(body) {
|
||||||
|
if (!body || (body && $scope.state.mailList.selected.decrypted === false)) {
|
||||||
|
$scope.node = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
// parse text nodes for rendering
|
||||||
|
$scope.node = $scope.parseConversation({
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function checkPublicKey(user) {
|
function checkPublicKey(user) {
|
||||||
@ -156,6 +171,114 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.parseConversation = function(email) {
|
||||||
|
var nodes;
|
||||||
|
|
||||||
|
if (!email || !email.body) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLines(body) {
|
||||||
|
var lines = [];
|
||||||
|
body.split('\n').forEach(parseLine);
|
||||||
|
|
||||||
|
function parseLine(line) {
|
||||||
|
var regex = /^>*/;
|
||||||
|
var result = regex.exec(line);
|
||||||
|
|
||||||
|
lines.push({
|
||||||
|
text: line.replace(regex, '').trim(),
|
||||||
|
level: (result && result.length > 0) ? result[0].length : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTextNodes(lines) {
|
||||||
|
var i, j, root, currentLevel, currentNode, levelDelta;
|
||||||
|
|
||||||
|
root = new Node();
|
||||||
|
currentLevel = 0;
|
||||||
|
currentNode = root;
|
||||||
|
|
||||||
|
// iterate over text lines
|
||||||
|
for (i = 0; i < lines.length; i++) {
|
||||||
|
levelDelta = lines[i].level - currentLevel;
|
||||||
|
|
||||||
|
if (levelDelta === 0) {
|
||||||
|
// we are at the desired node ... no traversal required
|
||||||
|
} else if (levelDelta > 0) {
|
||||||
|
// traverse to child node(s)
|
||||||
|
for (j = 0; j < levelDelta; j++) {
|
||||||
|
var newChild = new Node(currentNode);
|
||||||
|
// create new child node
|
||||||
|
currentNode.children.push(newChild);
|
||||||
|
// go to last child node
|
||||||
|
currentNode = newChild;
|
||||||
|
// increase current level by one
|
||||||
|
currentLevel++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// traverse to parent(s)
|
||||||
|
for (j = levelDelta; j < 0; j++) {
|
||||||
|
currentNode = currentNode.parent;
|
||||||
|
currentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add text to the current node
|
||||||
|
currentNode.addLine(lines[i].text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Node(parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.children = [];
|
||||||
|
}
|
||||||
|
Node.prototype.addLine = function(lineText) {
|
||||||
|
var c, l;
|
||||||
|
|
||||||
|
c = this.children;
|
||||||
|
l = c.length;
|
||||||
|
|
||||||
|
// append text node to children if last child is not a text node
|
||||||
|
if (l < 1 || typeof c[l - 1] !== 'string') {
|
||||||
|
c[l] = '';
|
||||||
|
l = c.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append line to last child (add newline between lines)
|
||||||
|
c[l - 1] += lineText + '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
function removeParentReference(node) {
|
||||||
|
if (!node.children) {
|
||||||
|
// this is a text leaf ... terminate recursion
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove parent node to prevent infinite loop in JSON stringify
|
||||||
|
delete node.parent;
|
||||||
|
|
||||||
|
for (var i = 0; i < node.children.length; i++) {
|
||||||
|
if (typeof node.children[i] === 'string') {
|
||||||
|
// remove trailing newline in string
|
||||||
|
node.children[i] = node.children[i].replace(/\n$/, '');
|
||||||
|
} else {
|
||||||
|
// I used recursion ...
|
||||||
|
removeParentReference(node.children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = buildTextNodes(parseLines(email.body.replace(/ >/g, '>')));
|
||||||
|
removeParentReference(nodes);
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -127,7 +127,7 @@ define(function(require) {
|
|||||||
|
|
||||||
// only display non html mails in reply part
|
// only display non html mails in reply part
|
||||||
if (!re.html) {
|
if (!re.html) {
|
||||||
body += re.body.trim().split('\n').join('\n> ');
|
body += re.body.trim().split('\n').join('\n> ').replace(/ >/g, '>');
|
||||||
$scope.body = body;
|
$scope.body = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,32 @@
|
|||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prev-message {
|
||||||
|
$prev-message-base-color: desaturate($color-blue, 50%);
|
||||||
|
$prev-message-hue-rotate: 40deg;
|
||||||
|
|
||||||
|
border-left: 2px solid $prev-message-base-color;
|
||||||
|
color: $prev-message-base-color;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
|
||||||
|
& > .prev-message {
|
||||||
|
border-left-color: adjust-hue($prev-message-base-color, 1 * $prev-message-hue-rotate);
|
||||||
|
color: adjust-hue($prev-message-base-color, 1 * $prev-message-hue-rotate);
|
||||||
|
& > .prev-message {
|
||||||
|
border-left-color: adjust-hue($prev-message-base-color, 2 * $prev-message-hue-rotate);
|
||||||
|
color: adjust-hue($prev-message-base-color, 2 * $prev-message-hue-rotate);
|
||||||
|
& > .prev-message {
|
||||||
|
border-left-color: adjust-hue($prev-message-base-color, 3 * $prev-message-hue-rotate);
|
||||||
|
color: adjust-hue($prev-message-base-color, 3 * $prev-message-hue-rotate);
|
||||||
|
.prev-message {
|
||||||
|
border-left-color: adjust-hue($prev-message-base-color, 4 * $prev-message-hue-rotate);
|
||||||
|
color: adjust-hue($prev-message-base-color, 4 * $prev-message-hue-rotate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
iframe {
|
||||||
|
@ -42,11 +42,14 @@
|
|||||||
|
|
||||||
<div class="body" ng-switch="state.mailList.selected === undefined || (state.mailList.selected.encrypted === false && state.mailList.selected.body !== undefined) || (state.mailList.selected.encrypted === true && state.mailList.selected.decrypted === true)">
|
<div class="body" ng-switch="state.mailList.selected === undefined || (state.mailList.selected.encrypted === false && state.mailList.selected.body !== undefined) || (state.mailList.selected.encrypted === true && state.mailList.selected.decrypted === true)">
|
||||||
<div ng-switch-when="true">
|
<div ng-switch-when="true">
|
||||||
<!-- Render lines of a text-email in divs for easier styling -->
|
|
||||||
<div class="line" ng-repeat="line in state.mailList.selected.body.split('\n') track by $index" ng-class="{'empty-line': lineEmpty(line)}">
|
<!-- Render conversation as recursive text nodes -->
|
||||||
<span ng-bind-html="line | createAnchors"></span>
|
<div ng-include="'tpl/text-node.html'"
|
||||||
<br>
|
ng-if="node !== undefined"
|
||||||
</div><!--/.line-->
|
ng-repeat="child in node.children track by $index"
|
||||||
|
onload="node = child">
|
||||||
|
</div>
|
||||||
|
|
||||||
</div><!--/ng-switch-when-->
|
</div><!--/ng-switch-when-->
|
||||||
<div class="working" ng-switch-default>
|
<div class="working" ng-switch-default>
|
||||||
<span class="spinner"></span>
|
<span class="spinner"></span>
|
||||||
|
16
src/tpl/text-node.html
Normal file
16
src/tpl/text-node.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!-- Render lines of a text-email in divs for easier styling -->
|
||||||
|
<div class="line"
|
||||||
|
ng-if="node.children === undefined"
|
||||||
|
ng-repeat="line in node.split('\n') track by $index"
|
||||||
|
ng-class="{'empty-line': lineEmpty(line)}">
|
||||||
|
<span ng-bind-html="line | createAnchors"></span>
|
||||||
|
<br>
|
||||||
|
</div><!--/.line-->
|
||||||
|
|
||||||
|
<!-- recursively render child node -->
|
||||||
|
<div class="prev-message"
|
||||||
|
ng-include="'tpl/text-node.html'"
|
||||||
|
ng-if="node.children !== undefined"
|
||||||
|
ng-repeat="child in node.children track by $index"
|
||||||
|
onload="node = child">
|
||||||
|
</div>
|
@ -166,5 +166,28 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('parseConversation', function() {
|
||||||
|
it('should work', function() {
|
||||||
|
var body = 'foo\n' +
|
||||||
|
'\n' +
|
||||||
|
'> bar\n' +
|
||||||
|
'>\n' +
|
||||||
|
'> foofoo\n' +
|
||||||
|
'>> foofoobar\n' +
|
||||||
|
'\ncomment\n' +
|
||||||
|
'>> barbar';
|
||||||
|
|
||||||
|
var nodes = scope.parseConversation({
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
expect(nodes).to.exist;
|
||||||
|
|
||||||
|
var expected = '{"children":["foo\\n",{"children":["bar\\n\\nfoofoo",{"children":["foofoobar"]}]},"\\ncomment",{"children":[{"children":["barbar"]}]}]}';
|
||||||
|
var json = JSON.stringify(nodes);
|
||||||
|
expect(json).to.equal(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user