summaryrefslogtreecommitdiff
path: root/web-ui
diff options
context:
space:
mode:
Diffstat (limited to 'web-ui')
-rw-r--r--web-ui/Makefile2
-rw-r--r--web-ui/app/index.html9
-rw-r--r--web-ui/app/js/dispatchers/right_pane_dispatcher.js10
-rw-r--r--web-ui/app/js/feedback/feedback_trigger.js39
-rw-r--r--web-ui/app/js/foundation/initialize_foundation.js3
-rw-r--r--web-ui/app/js/helpers/monitored_ajax.js6
-rw-r--r--web-ui/app/js/mail_view/data/feedback_sender.js49
-rw-r--r--web-ui/app/js/mail_view/data/mail_sender.js3
-rw-r--r--web-ui/app/js/mail_view/ui/compose_box.js2
-rw-r--r--web-ui/app/js/mail_view/ui/draft_box.js2
-rw-r--r--web-ui/app/js/mail_view/ui/draft_button.js41
-rw-r--r--web-ui/app/js/mail_view/ui/feedback_box.js65
-rw-r--r--web-ui/app/js/mail_view/ui/mail_view.js40
-rw-r--r--web-ui/app/js/main.js3
-rw-r--r--web-ui/app/js/mixins/with_mail_edit_base.js18
-rw-r--r--web-ui/app/js/page/default.js16
-rw-r--r--web-ui/app/js/page/events.js5
-rw-r--r--web-ui/app/js/page/pane_contract_expand.js1
-rw-r--r--web-ui/app/js/page/version.js31
-rw-r--r--web-ui/app/js/views/templates.js9
-rw-r--r--web-ui/app/locales/en/translation.json2
-rw-r--r--web-ui/app/locales/pt/translation.json2
-rw-r--r--web-ui/app/scss/_compose.scss35
-rw-r--r--web-ui/app/scss/_read.scss5
-rw-r--r--web-ui/app/scss/styles.scss29
-rw-r--r--web-ui/app/templates/compose/compose_box.hbs10
-rw-r--r--web-ui/app/templates/compose/feedback_box.hbs15
-rw-r--r--web-ui/app/templates/feedback/feedback_trigger.hbs8
-rw-r--r--web-ui/app/templates/mails/full_view.hbs2
-rw-r--r--web-ui/app/templates/page/version.hbs1
-rw-r--r--web-ui/bower.json3
-rwxr-xr-xweb-ui/config/add_git_version.sh14
-rw-r--r--web-ui/config/buildoptions.js1
-rw-r--r--web-ui/config/package.sh3
-rw-r--r--web-ui/package.json7
-rw-r--r--web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js9
-rw-r--r--web-ui/test/spec/feedback/feedback_trigger.spec.js38
-rw-r--r--web-ui/test/spec/mail_view/data/feedback_sender.spec.js27
-rw-r--r--web-ui/test/spec/mail_view/ui/compose_box.spec.js65
-rw-r--r--web-ui/test/spec/mail_view/ui/draft_box.spec.js15
-rw-r--r--web-ui/test/spec/mail_view/ui/draft_button.spec.js40
-rw-r--r--web-ui/test/spec/mail_view/ui/feedback_box.spec.js45
-rw-r--r--web-ui/test/spec/mail_view/ui/mail_view.spec.js10
-rw-r--r--web-ui/test/spec/page/pane_contract_expand.spec.js7
-rw-r--r--web-ui/test/test-main.js1
-rw-r--r--web-ui/test/test_data.js29
46 files changed, 714 insertions, 63 deletions
diff --git a/web-ui/Makefile b/web-ui/Makefile
index 383fecb7..0bc9d5d4 100644
--- a/web-ui/Makefile
+++ b/web-ui/Makefile
@@ -18,7 +18,7 @@ DESTDIR=target
compile:
npm install
- node_modules/bower/bin/bower install
+ node_modules/bower/bin/bower --allow-root install
./go package
clean:
diff --git a/web-ui/app/index.html b/web-ui/app/index.html
index cbdae267..281d661e 100644
--- a/web-ui/app/index.html
+++ b/web-ui/app/index.html
@@ -16,7 +16,6 @@
</head>
<body>
-
<div class="off-canvas-wrap move-right menu" data-offcanvas>
<div class="inner-wrap">
<section id="left-pane" class="left-off-canvas-menu">
@@ -49,6 +48,9 @@
</a>
<nav id="tag-list"></nav>
<div class="side-nav-bottom">
+ <div class="version">0.3.1-beta</div>
+
+ <nav id="feedback"></nav>
<nav id="logout"></nav>
</div>
</section>
@@ -58,7 +60,6 @@
<div class="off-canvas-wrap content" data-offcanvas>
<header id="main" >
<div id="user-alerts" class="message-panel"></div>
- <div id="loading" class="message-panel"><span>Loading...</span></div>
</header>
<div class="inner-wrap">
@@ -97,11 +98,9 @@
<script src="assets/bower_components/foundation/js/foundation.js" ></script>
<script src="assets/bower_components/foundation/js/foundation/foundation.reveal.js" ></script>
<script src="assets/bower_components/foundation/js/foundation/foundation.offcanvas.js"></script>
+<script src="assets/js/foundation/initialize_foundation.js"></script>
<script src="assets/bower_components/requirejs/require.js" data-main="assets/js/main.js"></script>
<!--usemin_end-->
-<script>
-$(document).foundation();
-</script>
</body>
</html>
diff --git a/web-ui/app/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js
index 8de89858..870bcd92 100644
--- a/web-ui/app/js/dispatchers/right_pane_dispatcher.js
+++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js
@@ -23,10 +23,11 @@ define(
'mail_view/ui/reply_section',
'mail_view/ui/draft_box',
'mail_view/ui/no_message_selected_pane',
+ 'mail_view/ui/feedback_box',
'page/events'
],
- function(defineComponent, ComposeBox, MailView, ReplySection, DraftBox, NoMessageSelectedPane, events) {
+ function(defineComponent, ComposeBox, MailView, ReplySection, DraftBox, NoMessageSelectedPane, FeedbackBox, events) {
'use strict';
return defineComponent(rightPaneDispatcher);
@@ -35,6 +36,7 @@ define(
this.defaultAttrs({
rightPane: '#right-pane',
composeBox: 'compose-box',
+ feedbackBox: 'feedback-box',
mailView: 'mail-view',
noMessageSelectedPane: 'no-message-selected-pane',
replySection: 'reply-section',
@@ -60,6 +62,11 @@ define(
ComposeBox.attachTo(stage, {currentTag: this.attr.currentTag});
};
+ this.openFeedbackBox = function() {
+ var stage = this.reset(this.attr.feedbackBox);
+ FeedbackBox.attachTo(stage);
+ };
+
this.openMail = function(ev, data) {
var stage = this.reset(this.attr.mailView);
MailView.attachTo(stage, data);
@@ -97,6 +104,7 @@ define(
this.on(document, events.dispatchers.rightPane.openComposeBox, this.openComposeBox);
this.on(document, events.dispatchers.rightPane.openDraft, this.openDraft);
this.on(document, events.ui.mail.open, this.openMail);
+ this.on(document, events.dispatchers.rightPane.openFeedbackBox, this.openFeedbackBox);
this.on(document, events.dispatchers.rightPane.openNoMessageSelected, this.openNoMessageSelectedPane);
this.on(document, events.dispatchers.rightPane.selectTag, this.selectTag);
this.on(document, events.ui.tag.selected, this.saveTag);
diff --git a/web-ui/app/js/feedback/feedback_trigger.js b/web-ui/app/js/feedback/feedback_trigger.js
new file mode 100644
index 00000000..598f9060
--- /dev/null
+++ b/web-ui/app/js/feedback/feedback_trigger.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define(['flight/lib/component', 'views/templates', 'page/events', 'features'],
+ function (defineComponent, templates, events, features) {
+ 'use strict';
+
+ return defineComponent(function () {
+ this.render = function () {
+ this.$node.html(templates.feedback.feedback());
+ };
+
+ this.onClick = function() {
+ this.trigger(document, events.dispatchers.rightPane.openFeedbackBox);
+ };
+
+ this.after('initialize', function () {
+ if (features.isEnabled('feedback')) {
+ this.render();
+ this.on('click', this.onClick);
+ }
+ });
+
+ });
+});
diff --git a/web-ui/app/js/foundation/initialize_foundation.js b/web-ui/app/js/foundation/initialize_foundation.js
new file mode 100644
index 00000000..b382a168
--- /dev/null
+++ b/web-ui/app/js/foundation/initialize_foundation.js
@@ -0,0 +1,3 @@
+'use strict';
+
+$(document).foundation();
diff --git a/web-ui/app/js/helpers/monitored_ajax.js b/web-ui/app/js/helpers/monitored_ajax.js
index 0068e10c..7f9a9beb 100644
--- a/web-ui/app/js/helpers/monitored_ajax.js
+++ b/web-ui/app/js/helpers/monitored_ajax.js
@@ -31,9 +31,6 @@ define(['page/events', 'views/i18n'], function (events, i18n) {
var originalBeforeSend = config.beforeSend;
config.beforeSend = function () {
- if (!config.skipLoadingWarning) {
- $('#loading').show();
- }
if (originalBeforeSend) {
originalBeforeSend();
}
@@ -41,9 +38,6 @@ define(['page/events', 'views/i18n'], function (events, i18n) {
var originalComplete = config.complete;
config.complete = function () {
- if (!config.skipLoadingWarning) {
- $('#loading').fadeOut(500);
- }
if (originalComplete) {
originalComplete();
}
diff --git a/web-ui/app/js/mail_view/data/feedback_sender.js b/web-ui/app/js/mail_view/data/feedback_sender.js
new file mode 100644
index 00000000..2232dbe4
--- /dev/null
+++ b/web-ui/app/js/mail_view/data/feedback_sender.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+define(
+ [
+ 'flight/lib/component',
+ 'helpers/monitored_ajax',
+ 'page/events'
+ ],
+ function (defineComponent, monitoredAjax, events) {
+ 'use strict';
+
+ return defineComponent(function () {
+ this.defaultAttrs({
+ feedbackResource: '/feedback'
+ });
+
+ this.successSubmittingFeedback = function() {
+ this.trigger(document, events.feedback.submitted);
+ };
+
+ this.submitFeedback = function(event, data) {
+ monitoredAjax.call(_, this, this.attr.feedbackResource, {
+ type: 'POST',
+ dataType: 'json',
+ contentType: 'application/json; charset=utf-8',
+ data: JSON.stringify(data)
+ }).done(this.successSubmittingFeedback());
+ };
+
+ this.after('initialize', function () {
+ this.on(document, events.feedback.submit, this.submitFeedback);
+ });
+
+ });
+});
diff --git a/web-ui/app/js/mail_view/data/mail_sender.js b/web-ui/app/js/mail_view/data/mail_sender.js
index c84a4f97..0d11c636 100644
--- a/web-ui/app/js/mail_view/data/mail_sender.js
+++ b/web-ui/app/js/mail_view/data/mail_sender.js
@@ -55,7 +55,7 @@ define(
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
- data: JSON.stringify(data),
+ data: JSON.stringify(data)
}).done(successSendingMail(this)).fail(failureSendingMail(this));
};
@@ -66,7 +66,6 @@ define(
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(mail),
- skipLoadingWarning: true,
skipErrorMessage: true
});
};
diff --git a/web-ui/app/js/mail_view/ui/compose_box.js b/web-ui/app/js/mail_view/ui/compose_box.js
index 1b209b23..28f6dc83 100644
--- a/web-ui/app/js/mail_view/ui/compose_box.js
+++ b/web-ui/app/js/mail_view/ui/compose_box.js
@@ -54,6 +54,8 @@ define(
this.renderComposeBox = function() {
this.render(templates.compose.box, {});
+ this.enableFloatlabel('input.floatlabel');
+ this.enableFloatlabel('textarea.floatlabel');
this.select('recipientsFields').show();
this.on(this.select('closeButton'), 'click', this.showNoMessageSelected);
this.enableAutoSave();
diff --git a/web-ui/app/js/mail_view/ui/draft_box.js b/web-ui/app/js/mail_view/ui/draft_box.js
index adad108f..8c2e15c7 100644
--- a/web-ui/app/js/mail_view/ui/draft_box.js
+++ b/web-ui/app/js/mail_view/ui/draft_box.js
@@ -66,6 +66,8 @@ define(
body: body
});
+ this.enableFloatlabel('input.floatlabel');
+ this.enableFloatlabel('textarea.floatlabel');
this.select('recipientsFields').show();
this.select('bodyBox').focus();
this.select('tipMsg').hide();
diff --git a/web-ui/app/js/mail_view/ui/draft_button.js b/web-ui/app/js/mail_view/ui/draft_button.js
new file mode 100644
index 00000000..1a89c414
--- /dev/null
+++ b/web-ui/app/js/mail_view/ui/draft_button.js
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2014 ThoughtWorks, Inc.
+*
+* Pixelated is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* Pixelated is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+*/
+'use strict';
+
+define([
+ 'flight/lib/component',
+ 'page/events',
+],
+function (defineComponent, events) {
+ return defineComponent(draftButton);
+
+ function draftButton() {
+ this.enableButton = function () {
+ this.$node.prop('disabled', false);
+ };
+
+ this.disableButton = function () {
+ this.$node.prop('disabled', true);
+ };
+
+ this.after('initialize', function(){
+ this.disableButton();
+ this.on(document, events.mail.saveDraft, this.disableButton);
+ this.on(document, events.mail.draftSaved, this.enableButton);
+ });
+ }
+});
diff --git a/web-ui/app/js/mail_view/ui/feedback_box.js b/web-ui/app/js/mail_view/ui/feedback_box.js
new file mode 100644
index 00000000..eb079b5b
--- /dev/null
+++ b/web-ui/app/js/mail_view/ui/feedback_box.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define(['flight/lib/component', 'views/templates', 'page/events', 'features'],
+ function (defineComponent, templates, events, features) {
+ 'use strict';
+
+ return defineComponent(function () {
+ this.defaultAttrs({
+ 'closeButton': '.close-mail-button',
+ 'submitButton': '#send-button',
+ 'textBox': '#text-box',
+ });
+
+ this.render = function () {
+ this.$node.html(templates.compose.feedback());
+ };
+
+ this.openFeedbackBox = function() {
+ var stage = this.reset('feedback-box');
+ this.attachTo(stage);
+ this.enableFloatlabel('input.floatlabel');
+ this.enableFloatlabel('textarea.floatlabel');
+ };
+
+ this.showNoMessageSelected = function() {
+ this.trigger(document, events.dispatchers.rightPane.openNoMessageSelected);
+ };
+
+ this.submitFeedback = function () {
+ var feedback = this.select('textBox').val();
+ this.trigger(document, events.feedback.submit, { feedback: feedback });
+ };
+
+ this.showSuccessMessage = function () {
+ this.trigger(document, events.ui.userAlerts.displayMessage, { message: 'Thanks for your feedback!' });
+ };
+
+ this.after('initialize', function () {
+ if (features.isEnabled('feedback')) {
+ this.render();
+ this.on(document, events.dispatchers.rightPane.openFeedbackBox, this.openFeedbackBox);
+ this.on(document, events.feedback.submitted, this.showNoMessageSelected);
+ this.on(document, events.feedback.submitted, this.showSuccessMessage);
+ this.on(this.select('closeButton'), 'click', this.showNoMessageSelected);
+ this.on(this.select('submitButton'), 'click', this.submitFeedback);
+ }
+ });
+
+ });
+});
diff --git a/web-ui/app/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js
index 71a67e5a..3c5b0ccc 100644
--- a/web-ui/app/js/mail_view/ui/mail_view.js
+++ b/web-ui/app/js/mail_view/ui/mail_view.js
@@ -25,11 +25,10 @@ define(
'mixins/with_hide_and_show',
'mixins/with_mail_tagging',
'page/events',
- 'views/i18n',
- 'features'
+ 'views/i18n'
],
- function (defineComponent, templates, mailActions, viewHelpers, withHideAndShow, withMailTagging, events, i18n, features) {
+ function (defineComponent, templates, mailActions, viewHelpers, withHideAndShow, withMailTagging, events, i18n) {
return defineComponent(mailView, mailActions, withHideAndShow, withMailTagging);
@@ -50,15 +49,15 @@ define(
var signed, encrypted;
data.mail.security_casing = data.mail.security_casing || {};
- if(features.isEnabled('signatureStatus')) {
- signed = this.checkSigned(data.mail);
- }
- if(features.isEnabled('encryptionStatus')) {
- encrypted = this.checkEncrypted(data.mail);
+ signed = this.checkSigned(data.mail);
+ encrypted = this.checkEncrypted(data.mail);
+
+ if(data.mail.mailbox === 'sent') {
+ encrypted = undefined;
}
var attachments = _.map(data.mail.attachments, function(a){
- return { 'encoding': a.headers['Content-Transfer-Encoding'], 'name': a.name, 'ident': a.ident };
+ return { 'encoding': a.encoding, 'name': a.name, 'ident': a.ident };
});
this.$node.html(templates.mails.fullView({
@@ -69,7 +68,6 @@ define(
tags: data.mail.tags,
encryptionStatus: encrypted,
signatureStatus: signed,
- features: features,
attachments: attachments
}));
@@ -104,16 +102,29 @@ define(
var status = ['encrypted'];
- if(_.any(mail.security_casing.locks, function (lock) { return lock.state === 'valid'; })) { status.push('encryption-valid'); }
- else { status.push('encryption-error'); }
+ var hasAnyEncryptionInfo = _.any(mail.security_casing.locks, function (lock) {
+ return lock.state === 'valid';
+ });
+
+ if(hasAnyEncryptionInfo) {
+ status.push('encryption-valid');
+ } else {
+ status.push('encryption-error');
+ }
return status.join(' ');
};
this.checkSigned = function(mail) {
- if(_.isEmpty(mail.security_casing.imprints)) { return 'not-signed'; }
+ if(_.isEmpty(mail.security_casing.imprints)) {
+ return 'not-signed';
+ }
+
+ var hasNoSignatureInformation = _.any(mail.security_casing.imprints, function (imprint) {
+ return imprint.state === 'no_signature_information';
+ });
- if(_.any(mail.security_casing.imprints, function(imprint) { return imprint.state === 'no_signature_information'; })) {
+ if(hasNoSignatureInformation) {
return '';
}
@@ -130,7 +141,6 @@ define(
status.push('signature-not-trusted');
}
-
return status.join(' ');
};
diff --git a/web-ui/app/js/main.js b/web-ui/app/js/main.js
index 06eca8dc..5bb1165c 100644
--- a/web-ui/app/js/main.js
+++ b/web-ui/app/js/main.js
@@ -21,6 +21,7 @@ requirejs.config({
paths: {
'mail_list': 'js/mail_list',
'page': 'js/page',
+ 'feedback': 'js/feedback',
'flight': 'bower_components/flight',
'hbs': 'js/generated/hbs',
'helpers': 'js/helpers',
@@ -35,9 +36,9 @@ requirejs.config({
'mixins': 'js/mixins',
'search': 'js/search',
'foundation': 'js/foundation',
+ 'features': 'js/features/features',
'i18next': 'bower_components/i18next/i18next.amd',
'quoted-printable': 'bower_components/quoted-printable',
- 'features': 'js/features/features',
'utf8': 'bower_components/utf8'
}
});
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 848fe026..b4a2b0c8 100644
--- a/web-ui/app/js/mixins/with_mail_edit_base.js
+++ b/web-ui/app/js/mixins/with_mail_edit_base.js
@@ -23,9 +23,10 @@ define(
'page/events',
'views/i18n',
'mail_view/ui/send_button',
+ 'mail_view/ui/draft_button',
'flight/lib/utils'
],
- function(viewHelper, Recipients, DraftSaveStatus, events, i18n, SendButton, utils) {
+ function(viewHelper, Recipients, DraftSaveStatus, events, i18n, SendButton, DraftButton, utils) {
'use strict';
function withMailEditBase() {
@@ -94,6 +95,7 @@ define(
this.on(this.select('draftButton'), 'click', this.buildAndSaveDraft);
this.on(this.select('trashButton'), 'click', this.trashMail);
SendButton.attachTo(this.select('sendButton'));
+ DraftButton.attachTo(this.select('draftButton'));
this.warnSendButtonOfRecipients();
};
@@ -203,6 +205,20 @@ define(
this.trigger(document, events.ui.userAlerts.displayMessage, { message: 'Your message was sent!' });
};
+ this.enableFloatlabel = function(element) {
+ var showClass = 'showfloatlabel';
+ $(element).bind('keyup', function() {
+ var label = $(this).prev('label');
+ if (this.value !== '') {
+ label.addClass(showClass);
+ $(this).addClass(showClass);
+ } else {
+ label.removeClass(showClass);
+ $(this).removeClass(showClass);
+ }
+ });
+ };
+
this.after('initialize', function () {
this.on(document, events.dispatchers.rightPane.clear, this.teardown);
this.on(document, events.ui.recipients.updated, this.recipientsUpdated);
diff --git a/web-ui/app/js/page/default.js b/web-ui/app/js/page/default.js
index 1571202e..1189d1ad 100644
--- a/web-ui/app/js/page/default.js
+++ b/web-ui/app/js/page/default.js
@@ -42,7 +42,11 @@ define(
'views/recipientListFormatter',
'flight/lib/logger',
'page/logout',
- 'page/logout_shortcut'
+ 'page/logout_shortcut',
+ 'feedback/feedback_trigger',
+ 'mail_view/ui/feedback_box',
+ 'mail_view/data/feedback_sender',
+ 'page/version',
],
function (
@@ -72,7 +76,11 @@ define(
recipientListFormatter,
withLogging,
logout,
- logoutShortcut) {
+ logoutShortcut,
+ feedback,
+ feedbackBox,
+ feedbackSender,
+ version) {
'use strict';
function initialize(path) {
@@ -105,6 +113,10 @@ define(
offCanvas.attachTo(document);
logout.attachTo('#logout');
logoutShortcut.attachTo('#logout-shortcut');
+ version.attachTo('.version');
+
+ feedback.attachTo('#feedback');
+ feedbackSender.attachTo(document);
}
return initialize;
diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js
index dfc2b852..cfc3d7db 100644
--- a/web-ui/app/js/page/events.js
+++ b/web-ui/app/js/page/events.js
@@ -100,6 +100,10 @@ define(function () {
highlightResults: 'search:highlightResults',
resetHighlight: 'search:resetHighlight'
},
+ feedback: {
+ submit: 'feedback:submit',
+ submitted: 'feedback:submitted'
+ },
mail: {
here: 'mail:here',
want: 'mail:want',
@@ -169,6 +173,7 @@ define(function () {
dispatchers: {
rightPane: {
openComposeBox: 'dispatchers:rightPane:openComposeBox',
+ openFeedbackBox: 'dispatchers:rightPane:openFeedbackBox',
openNoMessageSelected: 'dispatchers:rightPane:openNoMessageSelected',
openNoMessageSelectedWithoutPushState: 'dispatchers:rightPane:openNoMessageSelectedWithoutPushState',
refreshMailList: 'dispatchers:rightPane:refreshMailList',
diff --git a/web-ui/app/js/page/pane_contract_expand.js b/web-ui/app/js/page/pane_contract_expand.js
index 153e38e5..aee8c44f 100644
--- a/web-ui/app/js/page/pane_contract_expand.js
+++ b/web-ui/app/js/page/pane_contract_expand.js
@@ -42,6 +42,7 @@ define(['flight/lib/component', 'page/events'], function (describeComponent, eve
this.on(document, events.ui.mail.open, this.contractMiddlePaneExpandRightPane);
this.on(document, events.dispatchers.rightPane.openComposeBox, this.contractMiddlePaneExpandRightPane);
this.on(document, events.dispatchers.rightPane.openDraft, this.contractMiddlePaneExpandRightPane);
+ this.on(document, events.dispatchers.rightPane.openFeedbackBox, this.contractMiddlePaneExpandRightPane);
this.on(document, events.dispatchers.rightPane.openNoMessageSelected, this.expandMiddlePaneContractRightPane);
this.expandMiddlePaneContractRightPane();
});
diff --git a/web-ui/app/js/page/version.js b/web-ui/app/js/page/version.js
new file mode 100644
index 00000000..e5299f52
--- /dev/null
+++ b/web-ui/app/js/page/version.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+define(['flight/lib/component', 'views/templates'], function (defineComponent, templates) {
+ 'use strict';
+
+ return defineComponent(function () {
+
+ this.render = function () {
+ this.$node.html(templates.page.version());
+ };
+
+ this.after('initialize', function () {
+ this.render();
+ });
+
+ });
+});
diff --git a/web-ui/app/js/views/templates.js b/web-ui/app/js/views/templates.js
index 5e991a20..61fb0486 100644
--- a/web-ui/app/js/views/templates.js
+++ b/web-ui/app/js/views/templates.js
@@ -25,7 +25,8 @@ define(['hbs/templates'], function (templates) {
replySection: window.Pixelated['app/templates/compose/reply_section.hbs'],
recipientInput: window.Pixelated['app/templates/compose/recipient_input.hbs'],
fixedRecipient: window.Pixelated['app/templates/compose/fixed_recipient.hbs'],
- recipients: window.Pixelated['app/templates/compose/recipients.hbs']
+ recipients: window.Pixelated['app/templates/compose/recipients.hbs'],
+ feedback: window.Pixelated['app/templates/compose/feedback_box.hbs']
},
tags: {
tagList: window.Pixelated['app/templates/tags/tag_list.hbs'],
@@ -57,7 +58,11 @@ define(['hbs/templates'], function (templates) {
},
page: {
logout: window.Pixelated['app/templates/page/logout.hbs'],
- logoutShortcut: window.Pixelated['app/templates/page/logout_shortcut.hbs']
+ logoutShortcut: window.Pixelated['app/templates/page/logout_shortcut.hbs'],
+ version: window.Pixelated['app/templates/page/version.hbs']
+ },
+ feedback: {
+ feedback: window.Pixelated['app/templates/feedback/feedback_trigger.hbs']
}
};
diff --git a/web-ui/app/locales/en/translation.json b/web-ui/app/locales/en/translation.json
index a360cc02..5992216a 100644
--- a/web-ui/app/locales/en/translation.json
+++ b/web-ui/app/locales/en/translation.json
@@ -60,6 +60,8 @@
"Search results for:": "Search results for:",
"Tags": "Tags",
"Forward": "Forward",
+ "Submit Feedback": "Submit Feedback",
+ "feedback-placeholder": "Tell us what you like, didn't like, what is missing and generally what you think about Pixelated.",
"tags": {
"inbox": "Inbox",
diff --git a/web-ui/app/locales/pt/translation.json b/web-ui/app/locales/pt/translation.json
index 19b68c55..2885e12b 100644
--- a/web-ui/app/locales/pt/translation.json
+++ b/web-ui/app/locales/pt/translation.json
@@ -9,7 +9,7 @@
"Could not update mail tags": "Não foi possível atualizar as etiquetas do email",
"Invalid tag name": "Nome de etiqueta inválido",
"Could not delete email": "Não foi possível deletar o email",
- "Could not fetch messages": "Não foi possível buscar as mensagems",
+ "Could not fetch messages": "Não foi possível buscar as mensagens",
"sending-mail": "Enviando...",
"tags": {
diff --git a/web-ui/app/scss/_compose.scss b/web-ui/app/scss/_compose.scss
index acff745d..6f3ae29e 100644
--- a/web-ui/app/scss/_compose.scss
+++ b/web-ui/app/scss/_compose.scss
@@ -23,29 +23,50 @@
}
// COMPOSE PANE
-#compose-box, #draft-box, #reply-box {
+#compose-box, #draft-box, #reply-box, #feedback-box {
+ div.floatlabel {
+ position: relative;
+ }
margin: 5px 0 50px 30px;
padding: 0;
.input-container {
border-bottom: 1px solid #DDD;
padding: 1px;
}
- label {
+ label, span {
color: #AAA;
padding: 0.5rem;
cursor: text;
display: inline-block;
padding: 10px;
}
+ label.floatlabel {
+ padding: 0.4rem !important;
+ position: absolute;
+ font-size: 0.6rem;
+ transition: all 0.1s linear;
+ opacity: 0;
+ font-weight: bold;
+ }
+ label.showfloatlabel {
+ color: #64BCD0 !important;
+ top: -0.3rem;
+ opacity: 1;
+ }
input, textarea {
margin: 0;
border: none;
+ transition: all 0.1s linear;
}
- input {
- &#subject {
- font-size: 1.6875rem;
- line-height: 1.4;
- }
+ input.showfloatlabel, textarea.showfloatlabel {
+ padding-top: 1rem !important;
+ }
+ input#subject, #feedback-subject {
+ font-size: 1.6875rem;
+ line-height: 1.4;
+ }
+ #feedback-subject {
+ color: #333;
}
textarea {
border-bottom: 2px solid #DDD;
diff --git a/web-ui/app/scss/_read.scss b/web-ui/app/scss/_read.scss
index d621f672..24de425a 100644
--- a/web-ui/app/scss/_read.scss
+++ b/web-ui/app/scss/_read.scss
@@ -13,7 +13,6 @@
padding: 0px 0;
margin: 1px 0 0 0;
.recipients {
- border-bottom: 1px solid #DDD;
padding-bottom: 5px;
line-height: 1.5em;
i {
@@ -39,6 +38,10 @@
width:95%;
flex-shrink:1;
}
+ .headline-area {
+ clear: both;
+ border-top: 1px solid #DDD;
+ }
}
h3 {
margin-bottom: 0;
diff --git a/web-ui/app/scss/styles.scss b/web-ui/app/scss/styles.scss
index 4f2a56ee..7b1a2ec3 100644
--- a/web-ui/app/scss/styles.scss
+++ b/web-ui/app/scss/styles.scss
@@ -390,17 +390,15 @@ section {
}
}
- ul#logout {
+ ul#logout, ul#feedback {
li {
- color: $action_buttons;
background-color: $navigation_background;
padding: 5px 10px;
position: relative;
@include searching(4px, 19px, #333, 0.7em);
&:hover {
- background-color: $action_buttons;
- color: $navigation_background;
+ color: $navigation_background;
}
div {
@@ -417,6 +415,24 @@ section {
}
}
+ ul#logout li{
+ color: $action_buttons;
+ &:hover {
+ background-color: $action_buttons;
+ }
+ }
+
+ ul#feedback{
+ margin-bottom: 0;
+
+ li {
+ color: $light_orange;
+ &:hover {
+ background-color: $light_orange;
+ }
+ }
+ }
+
h3 {
color: white;
text-transform: uppercase;
@@ -774,6 +790,11 @@ div.side-nav-bottom {
position: fixed;
bottom: 0;
background-color: $navigation_background;
+
+ .version {
+ padding-left: 55px;
+ padding-bottom: 3px;
+ }
}
@import "mascot.scss";
diff --git a/web-ui/app/templates/compose/compose_box.hbs b/web-ui/app/templates/compose/compose_box.hbs
index d5501e69..2a1d27b0 100644
--- a/web-ui/app/templates/compose/compose_box.hbs
+++ b/web-ui/app/templates/compose/compose_box.hbs
@@ -1,8 +1,14 @@
<button class="close-mail-button">
<i class="fa fa-times"></i>
</button>
-<input type="text" id="subject" value="{{subject}}" placeholder="{{t 'Subject'}}" tabindex="1"/>
-<textarea id="text-box" placeholder="{{t 'Body'}}" tabindex="2">{{body}}</textarea>
+<div class="floatlabel">
+ <label class="floatlabel" for="subject">Subject</label>
+ <input class="floatlabel" name="subject" type="text" id="subject" value="{{subject}}" placeholder="{{t 'Subject'}}" tabindex="1"/>
+</div>
+<div class="floatlabel">
+ <label class="floatlabel" for="body">Body</label>
+ <textarea class="floatlabel" name="body" id="text-box" placeholder="{{t 'Body'}}" tabindex="2">{{body}}</textarea>
+</div>
{{> recipients }}
diff --git a/web-ui/app/templates/compose/feedback_box.hbs b/web-ui/app/templates/compose/feedback_box.hbs
new file mode 100644
index 00000000..ab5b3018
--- /dev/null
+++ b/web-ui/app/templates/compose/feedback_box.hbs
@@ -0,0 +1,15 @@
+<button class="close-mail-button">
+ <i class="fa fa-times"></i>
+</button>
+<div class="floatlabel">
+ <span id="feedback-subject">Feedback</span>
+</div>
+<div class="floatlabel">
+ <label class="floatlabel" for="text-box">Body</label>
+ <textarea class="floatlabel" name="body" id="text-box" placeholder="{{t 'feedback-placeholder'}}" tabindex="2">{{body}}</textarea>
+</div>
+
+
+<div class="buttons-group columns">
+ <button id="send-button" tabindex="6">{{t 'Submit Feedback'}} </button>
+</div>
diff --git a/web-ui/app/templates/feedback/feedback_trigger.hbs b/web-ui/app/templates/feedback/feedback_trigger.hbs
new file mode 100644
index 00000000..7f3f8ef1
--- /dev/null
+++ b/web-ui/app/templates/feedback/feedback_trigger.hbs
@@ -0,0 +1,8 @@
+<ul id="feedback">
+ <a title="Feedback" href="#">
+ <li>
+ <div class="fa fa-exclamation-circle"></div>
+ <i class="shortcut-label"></i> Feedback
+ </li>
+ </a>
+</ul>
diff --git a/web-ui/app/templates/mails/full_view.hbs b/web-ui/app/templates/mails/full_view.hbs
index 77994860..0383b821 100644
--- a/web-ui/app/templates/mails/full_view.hbs
+++ b/web-ui/app/templates/mails/full_view.hbs
@@ -36,7 +36,7 @@
<div class="recipients column large-2 text-right">
<span class="received-date">{{ formatDate header.date }}</span>
</div>
- <div>
+ <div class="headline-area">
<h3 class="subjectArea column large-10 no-padding">
<span class="subject">{{ header.subject }}</span>
diff --git a/web-ui/app/templates/page/version.hbs b/web-ui/app/templates/page/version.hbs
new file mode 100644
index 00000000..40804ff3
--- /dev/null
+++ b/web-ui/app/templates/page/version.hbs
@@ -0,0 +1 @@
+version: UNKNOWN_VERSION \ No newline at end of file
diff --git a/web-ui/bower.json b/web-ui/bower.json
index 3b51fefa..9d7a50c5 100644
--- a/web-ui/bower.json
+++ b/web-ui/bower.json
@@ -12,7 +12,8 @@
"quoted-printable": "0.2.1",
"typeahead.js": "~0.10.5",
"jasmine-flight": "~3.0.0",
- "utf8": "~2.0.0"
+ "utf8": "~2.0.0",
+ "modernizr": "~2.8.3"
},
"devDependencies": {
"handlebars": "2.0.0",
diff --git a/web-ui/config/add_git_version.sh b/web-ui/config/add_git_version.sh
new file mode 100755
index 00000000..2732abed
--- /dev/null
+++ b/web-ui/config/add_git_version.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+TEMPLATE_FILE="app/js/generated/hbs/templates.js"
+
+COMMITISH=$(git rev-parse --short HEAD)
+
+perl -pi -e "s/UNKNOWN_VERSION/$COMMITISH/" $TEMPLATE_FILE
+
+if [ ! -f "$TEMPLATE_FILE" ] ; then
+ echo "file $TEMPLATE_FILE not found" 1>&2
+ exit 1
+fi
+
+exit 0
diff --git a/web-ui/config/buildoptions.js b/web-ui/config/buildoptions.js
index 400dffb1..63c91653 100644
--- a/web-ui/config/buildoptions.js
+++ b/web-ui/config/buildoptions.js
@@ -25,4 +25,3 @@
include: ['js/main'],
name: 'bower_components/almond/almond'
})
-
diff --git a/web-ui/config/package.sh b/web-ui/config/package.sh
index f7d7f3aa..2ba5e1a0 100644
--- a/web-ui/config/package.sh
+++ b/web-ui/config/package.sh
@@ -28,6 +28,7 @@ mkdir -p dist
./go handlebars
./go imagemin
./go minify_html
+./go add_git_version
./go buildmain
@@ -47,7 +48,7 @@ app/bower_components/typeahead.js/dist/typeahead.bundle.min.js \
app/bower_components/foundation/js/foundation.js \
app/bower_components/foundation/js/foundation/foundation.reveal.js \
app/bower_components/foundation/js/foundation/foundation.offcanvas.js \
+app/js/foundation/initialize_foundation.js \
.tmp/app.concatenated.js > dist/app.js
node_modules/.bin/minify dist/app.js > dist/app.min.js
rm dist/app.js
-
diff --git a/web-ui/package.json b/web-ui/package.json
index 95d3ae72..f7c46a47 100644
--- a/web-ui/package.json
+++ b/web-ui/package.json
@@ -23,7 +23,7 @@
"watch": "0.14.0"
},
"scripts": {
- "test": "npm run build && node_modules/karma/bin/karma start --single-run --browsers PhantomJS $GRUNT_OPTS",
+ "test": "npm run jshint --silent && npm run build && node_modules/karma/bin/karma start --single-run --browsers PhantomJS $GRUNT_OPTS",
"debug": "npm run build && node_modules/karma/bin/karma start --browsers Chrome $GRUNT_OPTS",
"watch": "npm run compass-watch & npm run handlebars-watch",
"watch-test": "node_modules/karma/bin/karma start",
@@ -31,12 +31,13 @@
"handlebars-watch": "node_modules/.bin/watch 'npm run handlebars' app/templates",
"compass": "compass compile",
"compass-watch": "compass watch",
- "build": "npm run clean && npm run handlebars && npm run compass",
+ "build": "npm run clean && npm run handlebars && npm run add_git_version && npm run compass",
"jshint": "jshint --config=.jshintrc app test",
"clean": "rm -rf .tmp/ dist/**/* app/js/generated/hbs/* app/css/*",
"buildmain": "node_modules/requirejs/bin/r.js -o config/buildoptions.js",
"package": "/bin/bash config/package.sh",
"imagemin": "node config/imagemin.js",
- "minify_html": "node_modules/.bin/html-minifier app/index.html --collapse-whitespace | sed 's|<!--usemin_start-->.*<!--usemin_end-->|<script src=\"assets/app.min.js\" type=\"text/javascript\"></script>|' > dist/index.html"
+ "minify_html": "node_modules/.bin/html-minifier app/index.html --collapse-whitespace | sed 's|<!--usemin_start-->.*<!--usemin_end-->|<script src=\"assets/app.min.js\" type=\"text/javascript\"></script>|' > dist/index.html",
+ "add_git_version": "/bin/bash config/add_git_version.sh"
}
}
diff --git a/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js b/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js
index 4187610e..9df1d557 100644
--- a/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js
+++ b/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js
@@ -53,6 +53,14 @@ describeComponent('dispatchers/right_pane_dispatcher', function () {
expect(pushStateEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ isDisplayNoMessageSelected: true }));
});
+ it('listens to open feedback event and open feedback box', function () {
+ var feedbackBox = require('mail_view/ui/feedback_box');
+ spyOn(feedbackBox, 'attachTo');
+
+ this.component.trigger(document, Pixelated.events.dispatchers.rightPane.openFeedbackBox);
+
+ expect(feedbackBox.attachTo).toHaveBeenCalled();
+ });
});
@@ -66,6 +74,7 @@ describeComponent('dispatchers/right_pane_dispatcher', function () {
});
});
+
describe('on initialization', function () {
var noMessageSelectedPane;
diff --git a/web-ui/test/spec/feedback/feedback_trigger.spec.js b/web-ui/test/spec/feedback/feedback_trigger.spec.js
new file mode 100644
index 00000000..3860fc79
--- /dev/null
+++ b/web-ui/test/spec/feedback/feedback_trigger.spec.js
@@ -0,0 +1,38 @@
+describeComponent('feedback/feedback_trigger', function () {
+ 'use strict';
+
+ describe('Feedback link', function () {
+ var features;
+
+ beforeEach(function() {
+ features = require('features');
+ });
+
+ it('Should provide feedback link if logout is enabled', function () {
+ spyOn(features, 'isEnabled').and.returnValue(true);
+ this.setupComponent('<nav id="feedback"></nav>', {});
+
+ var feedback_link = this.component.$node.find('a')[0];
+ expect(feedback_link).toExist();
+ });
+
+ it('Should not provide feedback link if disabled', function() {
+ spyOn(features, 'isEnabled').and.returnValue(false);
+ this.setupComponent('<nav id="feedback"></nav>', {});
+
+ var feedback_link = this.component.$node.find('a')[0];
+ expect(feedback_link).not.toExist();
+ });
+
+ it('Should trigger ui:feedback:open event on click', function () {
+
+ this.setupComponent('<nav id="feedback"></nav>', {});
+ var spy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openFeedbackBox);
+
+ this.$node.find('a').click();
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+
+ });
+});
+
diff --git a/web-ui/test/spec/mail_view/data/feedback_sender.spec.js b/web-ui/test/spec/mail_view/data/feedback_sender.spec.js
new file mode 100644
index 00000000..30952c3f
--- /dev/null
+++ b/web-ui/test/spec/mail_view/data/feedback_sender.spec.js
@@ -0,0 +1,27 @@
+describeComponent('mail_view/data/feedback_sender', function () {
+ 'use strict';
+
+
+ beforeEach(function () {
+ this.setupComponent();
+ });
+
+ it('sends feedback with a POST to the server', function() {
+ var data = {feedback: 'Pixelated is awesome!'};
+ var feedbackSubmittedEventSpy = spyOnEvent(document, Pixelated.events.feedback.submitted);
+ var deferred = $.Deferred();
+
+ spyOn($, 'ajax').and.returnValue(deferred);
+
+ this.component.trigger(document, Pixelated.events.feedback.submit, data);
+
+ deferred.resolve();
+
+ expect(feedbackSubmittedEventSpy).toHaveBeenTriggeredOn(document);
+
+ expect($.ajax.calls.mostRecent().args[0]).toEqual('/feedback');
+ expect($.ajax.calls.mostRecent().args[1].type).toEqual('POST');
+ expect(JSON.parse($.ajax.calls.mostRecent().args[1].data)).toEqual(data);
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/ui/compose_box.spec.js b/web-ui/test/spec/mail_view/ui/compose_box.spec.js
index 414bc022..8e07481a 100644
--- a/web-ui/test/spec/mail_view/ui/compose_box.spec.js
+++ b/web-ui/test/spec/mail_view/ui/compose_box.spec.js
@@ -99,6 +99,15 @@ describeComponent('mail_view/ui/compose_box', function () {
expect(openNoMessageSelectedPaneEvent).not.toHaveBeenTriggeredOn(document);
});
+
+ it('should call the enableFloatlabel method when events.mail.here is trigged', function() {
+ spyOn(this.component, 'enableFloatlabel');
+
+ this.component.renderComposeBox();
+
+ expect(this.component.enableFloatlabel).toHaveBeenCalledWith('input.floatlabel');
+ expect(this.component.enableFloatlabel).toHaveBeenCalledWith('textarea.floatlabel');
+ });
});
describe('close button behavior', function() {
@@ -126,4 +135,60 @@ describeComponent('mail_view/ui/compose_box', function () {
}));
});
});
+
+ describe('subject label', function() {
+ var input;
+ var label;
+
+ beforeEach(function() {
+ input = $(this.component.$node).find('input');
+ label = input.prev('label');
+
+ this.component.enableFloatlabel(input);
+ });
+
+ it('should show the subject label after the user starts typing', function() {
+ input.val('test');
+ input.trigger('keyup');
+
+ expect(input.hasClass('showfloatlabel')).toEqual(true);
+ expect(label.hasClass('showfloatlabel')).toEqual(true);
+ });
+
+ it('should not show the subject label if the field is empty', function() {
+ input.val('');
+ input.trigger('keyup');
+
+ expect(input.hasClass('showfloatlabel')).toEqual(false);
+ expect(label.hasClass('showfloatlabel')).toEqual(false);
+ });
+ });
+
+ describe('body label', function() {
+ var textarea;
+ var label;
+
+ beforeEach(function() {
+ textarea = $(this.component.$node).find('textarea');
+ label = textarea.prev('label');
+
+ this.component.enableFloatlabel(textarea);
+ });
+
+ it('should show the subject label after the user starts typing', function() {
+ textarea.text('test');
+ textarea.trigger('keyup');
+
+ expect(textarea.hasClass('showfloatlabel')).toEqual(true);
+ expect(label.hasClass('showfloatlabel')).toEqual(true);
+ });
+
+ it('should not show the subject label if the field is empty', function() {
+ textarea.text('');
+ textarea.trigger('keyup');
+
+ expect(textarea.hasClass('showfloatlabel')).toEqual(false);
+ expect(label.hasClass('showfloatlabel')).toEqual(false);
+ });
+ });
});
diff --git a/web-ui/test/spec/mail_view/ui/draft_box.spec.js b/web-ui/test/spec/mail_view/ui/draft_box.spec.js
index 0113ca01..be3b4039 100644
--- a/web-ui/test/spec/mail_view/ui/draft_box.spec.js
+++ b/web-ui/test/spec/mail_view/ui/draft_box.spec.js
@@ -24,11 +24,8 @@ describeComponent('mail_view/ui/draft_box', function () {
});
describe('after initialize', function () {
- beforeEach(function () {
- this.setupComponent({mailIdent: '1'});
- });
-
it('renders the compose box when mail is received', function () {
+ this.setupComponent({mailIdent: '1'});
var templates = require('views/templates');
spyOn(this.component, 'render');
@@ -65,4 +62,14 @@ describeComponent('mail_view/ui/draft_box', function () {
expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
});
+ it('should call the enableFloatlabel method when events.mail.here is trigged', function() {
+ this.setupComponent({mailIdent: mail.ident});
+ spyOn(this.component, 'enableFloatlabel');
+
+ this.component.trigger(this.component, Pixelated.events.mail.here, { mail: mail });
+
+ expect(this.component.enableFloatlabel).toHaveBeenCalledWith('input.floatlabel');
+ expect(this.component.enableFloatlabel).toHaveBeenCalledWith('textarea.floatlabel');
+ });
+
});
diff --git a/web-ui/test/spec/mail_view/ui/draft_button.spec.js b/web-ui/test/spec/mail_view/ui/draft_button.spec.js
new file mode 100644
index 00000000..de607507
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/draft_button.spec.js
@@ -0,0 +1,40 @@
+/* global Pixelated */
+
+describeComponent('mail_view/ui/draft_button', function(){
+ 'use strict';
+
+ describe('draft save button', function(){
+ beforeEach(function(){
+ this.setupComponent('<button></button>');
+ });
+
+ describe('after initialize', function(){
+ it('should be disabled', function(){
+ expect(this.$node).toBeDisabled();
+ });
+ });
+
+ describe('when enabled', function(){
+ beforeEach(function(){
+ this.$node.prop('disabled', false);
+ });
+
+ it('should be disabled when saving draft message', function(){
+ $(document).trigger(Pixelated.events.mail.saveDraft, {});
+ expect(this.$node).toBeDisabled();
+ });
+ });
+
+ describe('when disabled', function(){
+ beforeEach(function(){
+ this.$node.prop('disabled', true);
+ });
+
+ it('should be enabled when draft message has been saved', function(){
+ $(document).trigger(Pixelated.events.mail.draftSaved, {});
+ expect(this.$node).not.toBeDisabled();
+ });
+ });
+
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/feedback_box.spec.js b/web-ui/test/spec/mail_view/ui/feedback_box.spec.js
new file mode 100644
index 00000000..4702672c
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/feedback_box.spec.js
@@ -0,0 +1,45 @@
+describeComponent('mail_view/ui/feedback_box', function () {
+ 'use strict';
+ beforeEach(function () {
+ Pixelated.mockBloodhound();
+ this.setupComponent('<div></div>');
+ });
+
+
+ describe('close button behavior', function() {
+
+ it('should fire Show no message selected if the close button is clicked', function() {
+ var spy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected);
+ this.component.select('closeButton').click();
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+
+ });
+
+ describe('when submit feedback', function () {
+
+ it('should fire submit feedback event', function () {
+ var spy = spyOnEvent(document, Pixelated.events.feedback.submit);
+
+ this.component.select('textBox').val('Pixelated is Awesome!');
+ this.component.select('submitButton').click();
+ expect(spy).toHaveBeenTriggeredOnAndWith(document, {feedback: 'Pixelated is Awesome!'});
+ });
+
+ it('should close feedback box after submit', function() {
+ var spy = spyOnEvent(document, Pixelated.events.dispatchers.rightPane.openNoMessageSelected);
+
+ this.component.trigger(document, Pixelated.events.feedback.submitted);
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+
+ it('should shows success message after submit', function () {
+ var spy = spyOnEvent(document, Pixelated.events.ui.userAlerts.displayMessage);
+
+ this.component.trigger(document, Pixelated.events.feedback.submitted);
+ expect(spy).toHaveBeenTriggeredOnAndWith(document, {message: 'Thanks for your feedback!'});
+ });
+
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/ui/mail_view.spec.js b/web-ui/test/spec/mail_view/ui/mail_view.spec.js
index deb7fb88..fe763919 100644
--- a/web-ui/test/spec/mail_view/ui/mail_view.spec.js
+++ b/web-ui/test/spec/mail_view/ui/mail_view.spec.js
@@ -265,6 +265,16 @@ describeComponent('mail_view/ui/mail_view', function () {
expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
});
+ it('shows a download link for attachments', function() {
+ var withAttachments = {mail: Pixelated.testData().parsedMail.withAttachments};
+
+ this.component.displayMail({}, withAttachments);
+
+ var attachmentLink = $(this.component.$node.find('.attachmentsArea li').html());
+ var expectedLink = '/attachment/912ec803b2ce49e4a541068d495ab570?encoding=base64&filename=filename.txt';
+ expect(attachmentLink.attr('href')) .toBe(expectedLink);
+ });
+
function creatingEvent(event, keyCode) {
var e = $.Event(event);
e.which = keyCode;
diff --git a/web-ui/test/spec/page/pane_contract_expand.spec.js b/web-ui/test/spec/page/pane_contract_expand.spec.js
index 4f4ff49b..6c7ebcfc 100644
--- a/web-ui/test/spec/page/pane_contract_expand.spec.js
+++ b/web-ui/test/spec/page/pane_contract_expand.spec.js
@@ -44,6 +44,13 @@ describeComponent('page/pane_contract_expand', function () {
expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_EXPAND_CLASSES);
});
+ it('contracts middle pane and expands right pane on open draft', function () {
+ $(document).trigger(Pixelated.events.dispatchers.rightPane.openFeedbackBox);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_CONTRACT_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_EXPAND_CLASSES);
+ });
+
it('expands middle pane and contracts right pane on event on open no message selected pane', function () {
$(document).trigger(Pixelated.events.dispatchers.rightPane.openNoMessageSelected);
diff --git a/web-ui/test/test-main.js b/web-ui/test/test-main.js
index 9cd5b12a..42ff1ba2 100644
--- a/web-ui/test/test-main.js
+++ b/web-ui/test/test-main.js
@@ -16,6 +16,7 @@ requirejs.config({
'flight': 'app/bower_components/flight',
'views': 'app/js/views',
'helpers': 'app/js/helpers',
+ 'feedback': 'app/js/feedback',
'tags': 'app/js/tags',
'mail_list': 'app/js/mail_list',
'mail_list_actions': 'app/js/mail_list_actions',
diff --git a/web-ui/test/test_data.js b/web-ui/test/test_data.js
index 446fd7c6..62492bbe 100644
--- a/web-ui/test/test_data.js
+++ b/web-ui/test/test_data.js
@@ -202,6 +202,32 @@ define(function() {
getMailPartByContentType: function () { return; }
};
+ var withAttachments = {
+ header: {
+ to:'jed_waelchi@cummerata.info',
+ from:'laurel@hamill.info',
+ subject:'Velit aut tempora animi ut nulla esse.',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident:1,
+ tags:['textplain'],
+ mailbox: ['inbox'],
+ status:[],
+ textPlainBody: 'Hello Everyone',
+ isSentMail: function() { return false; },
+ isDraftMail: function() { return false; },
+ replyToAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ replyToAllAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ isMailMultipartAlternative: function() { return false; },
+ availableBodyPartsContentType: function() { return []; },
+ getMailPartByContentType: function() { return; },
+ attachments: [{
+ ident: '912ec803b2ce49e4a541068d495ab570',
+ name: 'filename.txt',
+ encoding: 'base64'
+ }]
+ };
+
var testData = {
rawMail: {
mail: rawMail,
@@ -215,7 +241,8 @@ define(function() {
parsedMail: {
simpleTextPlain: simpleTextPlainMail,
html: htmlNoEncodingMail,
- draft: draftMail
+ draft: draftMail,
+ withAttachments: withAttachments
}
};