summaryrefslogtreecommitdiff
path: root/web-ui
diff options
context:
space:
mode:
Diffstat (limited to 'web-ui')
-rw-r--r--web-ui/app/js/helpers/view_helper.js13
-rw-r--r--web-ui/app/js/mail_list/ui/mail_item_factory.js6
-rw-r--r--web-ui/app/js/mixins/with_mail_edit_base.js4
-rw-r--r--web-ui/app/js/services/model/mail.js176
-rw-r--r--web-ui/app/js/tags/data/tags.js1
-rw-r--r--web-ui/app/js/tags/ui/tag_list.js1
-rw-r--r--web-ui/app/js/views/i18n.js8
-rw-r--r--web-ui/app/js/views/templates.js3
-rw-r--r--web-ui/app/locales/en-us/translation.json2
-rw-r--r--web-ui/app/locales/en/translation.json2
-rw-r--r--web-ui/app/scss/_mixins.scss10
-rw-r--r--web-ui/app/scss/_security.scss12
-rw-r--r--web-ui/app/templates/mails/full_view.hbs12
-rw-r--r--web-ui/app/templates/mails/single.hbs1
-rw-r--r--web-ui/app/templates/mails/trash.hbs26
-rw-r--r--web-ui/test/spec/helpers/view_helper.spec.js8
-rw-r--r--web-ui/test/spec/tags/data/tags.spec.js8
-rw-r--r--web-ui/test/spec/tags/ui/tag_list.spec.js7
18 files changed, 175 insertions, 125 deletions
diff --git a/web-ui/app/js/helpers/view_helper.js b/web-ui/app/js/helpers/view_helper.js
index 6755b891..a682ae5e 100644
--- a/web-ui/app/js/helpers/view_helper.js
+++ b/web-ui/app/js/helpers/view_helper.js
@@ -22,7 +22,7 @@ define(
'quoted-printable/quoted-printable',
'utf8/utf8'
],
- function(contentType, htmlWhitelister, i18n_lib, quotedPrintable, utf8) {
+ function(contentType, htmlWhitelister, i18n, quotedPrintable, utf8) {
'use strict';
function formatStatusClasses(ss) {
@@ -109,12 +109,15 @@ define(
}, 1);
}
- function quoteMail(mail) {
- return '\n\n' + mail.textPlainBody.replace(/^/mg, '> ');
+ function prependFrom(mail) {
+ return i18n(
+ 'On __date__, <__from__> wrote:\n',
+ {'date': new Date(mail.header.date).toString(), 'from': mail.header.from}
+ );
}
- function i18n(text) {
- return i18n_lib.get(text);
+ function quoteMail(mail) {
+ return '\n\n' + prependFrom(mail) + mail.textPlainBody.replace(/^/mg, '> ');
}
return {
diff --git a/web-ui/app/js/mail_list/ui/mail_item_factory.js b/web-ui/app/js/mail_list/ui/mail_item_factory.js
index 87a883b0..3c815401 100644
--- a/web-ui/app/js/mail_list/ui/mail_item_factory.js
+++ b/web-ui/app/js/mail_list/ui/mail_item_factory.js
@@ -26,12 +26,14 @@ define(
var MAIL_ITEM_TYPE = {
'drafts': DraftItem,
- 'sent': SentItem
+ 'sent': SentItem,
+ 'trash': GenericMailItem
};
var TEMPLATE_TYPE = {
'drafts': 'draft',
- 'sent': 'sent'
+ 'sent': 'sent',
+ 'trash': 'trash'
};
var createAndAttach = function (nodeToAttachTo, mail, currentMailIdent, currentTag, isChecked) {
diff --git a/web-ui/app/js/mixins/with_mail_edit_base.js b/web-ui/app/js/mixins/with_mail_edit_base.js
index 9942e747..5efb8967 100644
--- a/web-ui/app/js/mixins/with_mail_edit_base.js
+++ b/web-ui/app/js/mixins/with_mail_edit_base.js
@@ -134,7 +134,7 @@ define(
} else {
this.trigger(
events.ui.userAlerts.displayMessage,
- {message: i18n.get('One or more of the recipients are not valid emails')}
+ {message: i18n('One or more of the recipients are not valid emails')}
);
this.trigger(events.mail.send_failed);
}
@@ -176,7 +176,7 @@ define(
this.draftSaved = function(event, data) {
this.attr.ident = data.ident;
if(!this.attr.silent) {
- this.trigger(document, events.ui.userAlerts.displayMessage, { message: i18n.get('Saved as draft.') });
+ this.trigger(document, events.ui.userAlerts.displayMessage, { message: i18n('Saved as draft.') });
}
delete this.attr.silent;
};
diff --git a/web-ui/app/js/services/model/mail.js b/web-ui/app/js/services/model/mail.js
index 34cba610..c41bcff9 100644
--- a/web-ui/app/js/services/model/mail.js
+++ b/web-ui/app/js/services/model/mail.js
@@ -16,121 +16,111 @@
*/
'use strict';
-define(['helpers/contenttype'],
- function (contentType) {
-
- var asMail = (function () {
-
- function isSentMail() {
- return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'SENT';
- }
-
- function isDraftMail() {
- return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'DRAFTS';
- }
-
- function isInTrash() {
- return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'TRASH';
- }
-
- function setDraftReplyFor(ident) {
- this.draft_reply_for = ident;
- }
-
- function replyToAddress() {
- return {
- to: [this.replying.single],
- cc: []
- };
- }
-
- function replyToAllAddress() {
- return {
- to: this.replying.all['to-field'],
- cc: this.replying.all['cc-field']
- };
- }
+define(['helpers/contenttype'], function (contentType) {
+ function isSentMail() {
+ return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'SENT';
+ }
+
+ function isDraftMail() {
+ return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'DRAFTS';
+ }
+
+ function isInTrash() {
+ return _.has(this, 'mailbox') && this.mailbox.toUpperCase() === 'TRASH';
+ }
+
+ function setDraftReplyFor(ident) {
+ this.draft_reply_for = ident;
+ }
+
+ function replyToAddress() {
+ return {
+ to: [this.replying.single],
+ cc: []
+ };
+ }
- function getHeadersFromMailPart (rawBody) {
- var lines, headerLines, endOfHeaders, headers;
+ function replyToAllAddress() {
+ return {
+ to: this.replying.all['to-field'],
+ cc: this.replying.all['cc-field']
+ };
+ }
- lines = rawBody.split('\n');
- endOfHeaders = _.indexOf(lines, '');
- headerLines = lines.slice(0, endOfHeaders);
+ function getHeadersFromMailPart (rawBody) {
+ var lines, headerLines, endOfHeaders, headers;
- headers = _.map(headerLines, function (headerLine) {
- return _.map(headerLine.split(':'), function(elem){return elem.trim();});
- });
+ lines = rawBody.split('\n');
+ endOfHeaders = _.indexOf(lines, '');
+ headerLines = lines.slice(0, endOfHeaders);
- return _.object(headers);
- }
+ headers = _.map(headerLines, function (headerLine) {
+ return _.map(headerLine.split(':'), function(elem){return elem.trim();});
+ });
- function getBodyFromMailPart (rawBody) {
- var lines, endOfHeaders;
+ return _.object(headers);
+ }
- lines = rawBody.split('\n');
- endOfHeaders = _.indexOf(lines, '');
+ function getBodyFromMailPart (rawBody) {
+ var lines, endOfHeaders;
- return lines.slice(endOfHeaders + 1).join('\n');
- }
+ lines = rawBody.split('\n');
+ endOfHeaders = _.indexOf(lines, '');
- function parseWithHeaders(rawBody) {
- return {headers: getHeadersFromMailPart(rawBody), body: getBodyFromMailPart(rawBody)};
- }
+ return lines.slice(endOfHeaders + 1).join('\n');
+ }
- function getMailMultiParts () {
- var mediaType = this.getMailMediaType();
- var boundary = '--' + mediaType.params.boundary + '\n';
- var finalBoundary = '--' + mediaType.params.boundary + '--';
+ function parseWithHeaders(rawBody) {
+ return {headers: getHeadersFromMailPart(rawBody), body: getBodyFromMailPart(rawBody)};
+ }
- var bodyParts = this.body.split(finalBoundary)[0].split(boundary);
+ function getMailMultiParts () {
+ var mediaType = this.getMailMediaType();
+ var boundary = '--' + mediaType.params.boundary + '\n';
+ var finalBoundary = '--' + mediaType.params.boundary + '--';
- bodyParts = _.reject(bodyParts, function(bodyPart) { return _.isEmpty(bodyPart.trim()); });
+ var bodyParts = this.body.split(finalBoundary)[0].split(boundary);
- return _.map(bodyParts, parseWithHeaders);
- }
+ bodyParts = _.reject(bodyParts, function(bodyPart) { return _.isEmpty(bodyPart.trim()); });
- function getMailMediaType () {
- return new contentType.MediaType(this.header.content_type);
- }
+ return _.map(bodyParts, parseWithHeaders);
+ }
- function isMailMultipartAlternative () {
- return this.getMailMediaType().type === 'multipart/alternative';
- }
+ function getMailMediaType () {
+ return new contentType.MediaType(this.header.content_type);
+ }
- function availableBodyPartsContentType () {
- var bodyParts = this.getMailMultiParts();
+ function isMailMultipartAlternative () {
+ return this.getMailMediaType().type === 'multipart/alternative';
+ }
- return _.pluck(_.pluck(bodyParts, 'headers'), 'Content-Type');
- }
+ function availableBodyPartsContentType () {
+ var bodyParts = this.getMailMultiParts();
- function getMailPartByContentType (contentType) {
- var bodyParts = this.getMailMultiParts();
+ return _.pluck(_.pluck(bodyParts, 'headers'), 'Content-Type');
+ }
- return _.findWhere(bodyParts, {headers: {'Content-Type': contentType}});
- }
+ function getMailPartByContentType (contentType) {
+ var bodyParts = this.getMailMultiParts();
- return function () {
- this.isSentMail = isSentMail;
- this.isDraftMail = isDraftMail;
- this.isInTrash = isInTrash;
- this.setDraftReplyFor = setDraftReplyFor;
- this.replyToAddress = replyToAddress;
- this.replyToAllAddress = replyToAllAddress;
- this.getMailMediaType = getMailMediaType;
- this.isMailMultipartAlternative = isMailMultipartAlternative;
- this.getMailMultiParts = getMailMultiParts;
- this.availableBodyPartsContentType = availableBodyPartsContentType;
- this.getMailPartByContentType = getMailPartByContentType;
- return this;
- };
- }());
+ return _.findWhere(bodyParts, {headers: {'Content-Type': contentType}});
+ }
return {
create: function (mail) {
- if (mail) {
- asMail.apply(mail);
- }
+ if (!mail) { return; }
+
+ mail.isSentMail = isSentMail;
+ mail.isDraftMail = isDraftMail;
+ mail.isInTrash = isInTrash;
+ mail.setDraftReplyFor = setDraftReplyFor;
+ mail.replyToAddress = replyToAddress;
+ mail.replyToAllAddress = replyToAllAddress;
+ mail.getMailMediaType = getMailMediaType;
+ mail.isMailMultipartAlternative = isMailMultipartAlternative;
+ mail.getMailMultiParts = getMailMultiParts;
+ mail.availableBodyPartsContentType = availableBodyPartsContentType;
+ mail.getMailPartByContentType = getMailPartByContentType;
return mail;
}
};
diff --git a/web-ui/app/js/tags/data/tags.js b/web-ui/app/js/tags/data/tags.js
index 401b41f7..348c1832 100644
--- a/web-ui/app/js/tags/data/tags.js
+++ b/web-ui/app/js/tags/data/tags.js
@@ -57,6 +57,7 @@ define(['flight/lib/component', 'page/events', 'helpers/monitored_ajax', 'mixins
this.after('initialize', function () {
this.on(document, events.tags.want, this.fetchTags);
+ this.on(document, events.mail.sent, this.fetchTags);
});
}
diff --git a/web-ui/app/js/tags/ui/tag_list.js b/web-ui/app/js/tags/ui/tag_list.js
index a2172c6d..d6f6f76c 100644
--- a/web-ui/app/js/tags/ui/tag_list.js
+++ b/web-ui/app/js/tags/ui/tag_list.js
@@ -98,6 +98,7 @@ define(
this.after('initialize', function() {
this.on(document, events.tags.received, this.displayTags);
this.on(document, events.ui.tag.select, this.updateCurrentTag);
+ this.on(document, events.ui.tag.select, events.ui.mails.uncheckAll);
this.renderTagListTemplate();
});
}
diff --git a/web-ui/app/js/views/i18n.js b/web-ui/app/js/views/i18n.js
index b09490f5..568e7635 100644
--- a/web-ui/app/js/views/i18n.js
+++ b/web-ui/app/js/views/i18n.js
@@ -17,15 +17,11 @@
define(['i18next'], function(i18n) {
'use strict';
- var self = function(str) {
- return i18n.t(str);
- };
-
- self.get = self;
+ var self = i18n.t;
self.init = function(path) {
i18n.init({detectLngQS: 'lang', fallbackLng: 'en', lowerCaseLng: true, getAsync: false, resGetPath: path + 'locales/__lng__/__ns__.json'});
- Handlebars.registerHelper('t', self.get.bind(self));
+ Handlebars.registerHelper('t', self.bind(self));
};
return self;
diff --git a/web-ui/app/js/views/templates.js b/web-ui/app/js/views/templates.js
index 470c6e51..64e269ca 100644
--- a/web-ui/app/js/views/templates.js
+++ b/web-ui/app/js/views/templates.js
@@ -41,7 +41,8 @@ define(['hbs/templates'], function (templates) {
fullView: window.Pixelated['app/templates/mails/full_view.hbs'],
mailActions: window.Pixelated['app/templates/mails/mail_actions.hbs'],
draft: window.Pixelated['app/templates/mails/draft.hbs'],
- sent: window.Pixelated['app/templates/mails/sent.hbs']
+ sent: window.Pixelated['app/templates/mails/sent.hbs'],
+ trash: window.Pixelated['app/templates/mails/trash.hbs']
},
mailActions: {
actionsBox: window.Pixelated['app/templates/mail_actions/actions_box.hbs'],
diff --git a/web-ui/app/locales/en-us/translation.json b/web-ui/app/locales/en-us/translation.json
index 2a474c80..b6fd6f0a 100644
--- a/web-ui/app/locales/en-us/translation.json
+++ b/web-ui/app/locales/en-us/translation.json
@@ -46,7 +46,7 @@
"encrypted encryption-error": "Unable to decrypt",
"encrypted encryption-valid": "Encrypted",
"not-encrypted": "Not Encrypted",
- "signed": "Certified sender.",
+ "signed": "Certified sender",
"signed signature-revoked": "Sender could not be securely identified.",
"signed signature-expired": "Sender could not be securely identified.",
"signed signature-not-trusted": "Sender and/or message cannot be trusted.",
diff --git a/web-ui/app/locales/en/translation.json b/web-ui/app/locales/en/translation.json
index 2a474c80..b6fd6f0a 100644
--- a/web-ui/app/locales/en/translation.json
+++ b/web-ui/app/locales/en/translation.json
@@ -46,7 +46,7 @@
"encrypted encryption-error": "Unable to decrypt",
"encrypted encryption-valid": "Encrypted",
"not-encrypted": "Not Encrypted",
- "signed": "Certified sender.",
+ "signed": "Certified sender",
"signed signature-revoked": "Sender could not be securely identified.",
"signed signature-expired": "Sender could not be securely identified.",
"signed signature-not-trusted": "Sender and/or message cannot be trusted.",
diff --git a/web-ui/app/scss/_mixins.scss b/web-ui/app/scss/_mixins.scss
index 14a1679f..2ce4999a 100644
--- a/web-ui/app/scss/_mixins.scss
+++ b/web-ui/app/scss/_mixins.scss
@@ -81,6 +81,12 @@
}
@mixin tags {
+ i.tags-label {
+ vertical-align: bottom;
+ font-size: medium;
+ color: #c2c2c2;
+ }
+
ul.tags {
li {
font-size: 0.6rem;
@@ -105,7 +111,8 @@
background: transparent;
border: 1px solid #DDD;
line-height: 0;
- padding: 3px 2px 2px 2px;
+ padding: 1px 2px;
+ margin-left: -5px;
@include border-radius(2px);
&:hover {
opacity: 1;
@@ -114,6 +121,7 @@
i {
&:before {
vertical-align: middle;
+ font-size: smaller;
}
}
}
diff --git a/web-ui/app/scss/_security.scss b/web-ui/app/scss/_security.scss
index be306d86..0c2baa52 100644
--- a/web-ui/app/scss/_security.scss
+++ b/web-ui/app/scss/_security.scss
@@ -12,35 +12,35 @@
}
&.encrypted {
&:before {
- content: "\f023 \f00c";
+ content: "\f023";
}
&.encryption-error {
background: $attention;
&:before {
- content: "\f023 \f12a";
+ content: "\f023 \f057";
}
}
}
&.signed {
&:before {
- content: "\f007 \f00c";
+ content: "\f00c";
}
&.signature-not-trusted {
background: $error;
&:before {
- content: "\f007 \f05e";
+ content: "\f05e";
}
}
}
&[class^=not-], &.signature-expired, &.signature-revoked {
background: $attention;
&:before {
- content: "\f007 \f12a"
+ content: "\f05e"
}
}
&.not-encrypted {
&:before {
- content: "\f023 \f12a";
+ content: "\f13e ";
}
}
}
diff --git a/web-ui/app/templates/mails/full_view.hbs b/web-ui/app/templates/mails/full_view.hbs
index c72b3af9..55d116d2 100644
--- a/web-ui/app/templates/mails/full_view.hbs
+++ b/web-ui/app/templates/mails/full_view.hbs
@@ -10,7 +10,7 @@
<div style="display:inline-block;padding-top: 5px;width:95%;flex-shrink:1" >
- <div class="column large-10 no-padding security-status">
+ <div class="column large-12 no-padding security-status">
{{#if signatureStatus}}
<span class="{{signatureStatus}}">
{{t signatureStatus }}
@@ -22,10 +22,7 @@
</span>
{{/if}}
</div>
- <div class="column large-2 no-padding text-right">
- <span class="received-date">{{ header.formattedDate }}</span>
- </div>
- <div class="recipients column large-12 no-padding">
+ <div class="recipients column large-10 no-padding">
<span class="from">
{{#if header.from }}
{{ header.from }}
@@ -36,13 +33,16 @@
<i class="fa fa-long-arrow-right"></i>
{{{formatRecipients header}}}
</div>
-
+ <div class="recipients column large-2 text-right">
+ <span class="received-date">{{ header.formattedDate }}</span>
+ </div>
<div>
<h3 class="subjectArea column large-10 no-padding">
<span class="subject">{{ header.subject }}</span>
<div class="tagsArea">
<ul class="tags">
+ <i class="tags-label fa fa-tags"></i>
{{#each tags }}
<li class="tag" data-tag="{{this}}">{{ this }}</li>
{{/each }}
diff --git a/web-ui/app/templates/mails/single.hbs b/web-ui/app/templates/mails/single.hbs
index a74c9606..90023713 100644
--- a/web-ui/app/templates/mails/single.hbs
+++ b/web-ui/app/templates/mails/single.hbs
@@ -12,7 +12,6 @@
</span>
<div class="from">{{#if header.from }}{{ header.from }}{{else}}{{t "you"}}{{/if}}</div>
<div class="subject-and-tags">
- <i class="fa fa-trash-o"></i>
{{ header.subject }}
</div>
<div class="subject-and-tags">
diff --git a/web-ui/app/templates/mails/trash.hbs b/web-ui/app/templates/mails/trash.hbs
new file mode 100644
index 00000000..a74c9606
--- /dev/null
+++ b/web-ui/app/templates/mails/trash.hbs
@@ -0,0 +1,26 @@
+<span>
+ <input type="checkbox" {{#if isChecked }}checked="true"{{/if}} />
+</span>
+<span>
+ <a href="/#/{{ tag }}/mail/{{ ident }}">
+ <span class="received-date">{{ header.formattedDate }}
+ {{#if attachments}}
+ <div class="attachment-indicator">
+ <i class="fa fa-paperclip"></i>
+ </div>
+ {{/if}}
+ </span>
+ <div class="from">{{#if header.from }}{{ header.from }}{{else}}{{t "you"}}{{/if}}</div>
+ <div class="subject-and-tags">
+ <i class="fa fa-trash-o"></i>
+ {{ header.subject }}
+ </div>
+ <div class="subject-and-tags">
+ <ul class="tags">
+ {{#each tagsForListView }}
+ <li class="tag" data-tag="{{this}}">{{ this }}</li>
+ {{/each }}
+ </ul>
+ </div>
+ </a>
+</span>
diff --git a/web-ui/test/spec/helpers/view_helper.spec.js b/web-ui/test/spec/helpers/view_helper.spec.js
index 7b5b960b..888c6cda 100644
--- a/web-ui/test/spec/helpers/view_helper.spec.js
+++ b/web-ui/test/spec/helpers/view_helper.spec.js
@@ -15,6 +15,14 @@ define(['helpers/view_helper'], function (viewHelper) {
expect(quotedMail).toContain('> First Line\n> Second Line');
});
+
+ it('should add the mail sender information', function() {
+ testData.rawMail.mail.textPlainBody = 'First Line\nSecond Line';
+
+ var quotedMail = viewHelper.quoteMail(testData.rawMail.mail);
+
+ expect(quotedMail).toContain('On Wed Jun 04 2014 17:41:13 GMT+0000 (UTC), <laurel@hamill.info> wrote');
+ });
});
describe('getFormmattedDate', function() {
diff --git a/web-ui/test/spec/tags/data/tags.spec.js b/web-ui/test/spec/tags/data/tags.spec.js
index 469ab0ce..53978fb8 100644
--- a/web-ui/test/spec/tags/data/tags.spec.js
+++ b/web-ui/test/spec/tags/data/tags.spec.js
@@ -47,4 +47,12 @@ describeComponent('tags/data/tags', function () {
tags.push(this.component.all);
expect(eventSpy.mostRecentCall.data).toEqual(jasmine.objectContaining({tags: tags}));
});
+
+ it('should reload taglist on mail sent', function(){
+ spyOn($, 'ajax').and.returnValue($.Deferred());
+
+ $(document).trigger(Pixelated.events.mail.sent);
+
+ expect($.ajax.calls.mostRecent().args[0]).toEqual('/tags');
+ });
});
diff --git a/web-ui/test/spec/tags/ui/tag_list.spec.js b/web-ui/test/spec/tags/ui/tag_list.spec.js
index f92f72af..e84c68aa 100644
--- a/web-ui/test/spec/tags/ui/tag_list.spec.js
+++ b/web-ui/test/spec/tags/ui/tag_list.spec.js
@@ -62,6 +62,13 @@ describeComponent('tags/ui/tag_list', function () {
expect(this.component.attr.currentTag).toEqual('amazing');
});
+ it('should uncheck all emails when a new tag is selected', function () {
+ var uncheckAllEvent = spyOnEvent(document, Pixelated.events.ui.mails.uncheckAll);
+ $(document).trigger(Pixelated.events.ui.tag.select, { tag: 'amazing'});
+
+ expect(uncheckAllEvent).toHaveBeenTriggeredOn(document);
+ });
+
it('resets the tag lists when loading tags', function () {
var tagList = [tag('tag1', 1, false), tag('tag2', 2, true), tag('tag3', 3, true)];
$(document).trigger(Pixelated.events.tags.received, {tags: tagList});