summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNavaL <mnandri@thoughtworks.com>2015-12-22 18:58:57 +0100
committerNavaL <mnandri@thoughtworks.com>2015-12-22 19:05:10 +0100
commitec3a7f46f16c32bbaf22a14a92a890e1ab900e94 (patch)
tree4e900828ccbc1d7be63b73d5e6253acc40e901aa
parent4cb47c1848bb5d20b5ae167a7ab2879d00825f84 (diff)
front-end for sending attachments
Issue #548
-rw-r--r--web-ui/app/index.html3
-rw-r--r--web-ui/app/js/features/features.js4
-rw-r--r--web-ui/app/js/mail_view/data/attachment_list.js40
-rw-r--r--web-ui/app/js/mail_view/data/mail_builder.js130
-rw-r--r--web-ui/app/js/mail_view/ui/attachment.js68
-rw-r--r--web-ui/app/js/mail_view/ui/compose_box.js8
-rw-r--r--web-ui/app/js/mixins/with_mail_edit_base.js5
-rw-r--r--web-ui/app/js/page/events.js3
-rw-r--r--web-ui/app/scss/styles.scss4
-rw-r--r--web-ui/app/templates/compose/compose_box.hbs34
-rw-r--r--web-ui/bower.json4
-rw-r--r--web-ui/karma.conf.js2
-rw-r--r--web-ui/test/spec/mail_view/data/attachment_list.spec.js21
-rw-r--r--web-ui/test/spec/mail_view/data/mail_builder.spec.js8
-rw-r--r--web-ui/test/spec/mail_view/ui/attachment.spec.js24
15 files changed, 278 insertions, 80 deletions
diff --git a/web-ui/app/index.html b/web-ui/app/index.html
index a302992c..9ffeee82 100644
--- a/web-ui/app/index.html
+++ b/web-ui/app/index.html
@@ -10,6 +10,7 @@
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<link href="assets/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+<link href="assets/bower_components/jquery-file-upload/css/jquery.fileupload.css" rel="stylesheet" type="text/css">
<link href="assets/css/opensans.css" rel="stylesheet" type="text/css">
<link href="assets/css/news-cycle.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="assets/css/main.css">
@@ -93,6 +94,8 @@
<script src="assets/bower_components/modernizr/modernizr.js"></script>
<script src="assets/bower_components/lodash/dist/lodash.js"></script>
<script src="assets/bower_components/jquery/dist/jquery.js"></script>
+<script src="assets/bower_components/jquery-ui/jquery-ui.min.js"></script>
+<script src="assets/bower_components/jquery-file-upload/js/jquery.fileupload.js"></script>
<script src="assets/js/lib/highlightRegex.js"></script>
<script src="assets/bower_components/handlebars/handlebars.min.js"></script>
<script src="assets/bower_components/typeahead.js/dist/typeahead.bundle.min.js"></script>
diff --git a/web-ui/app/js/features/features.js b/web-ui/app/js/features/features.js
index 9c791ccd..4d04df64 100644
--- a/web-ui/app/js/features/features.js
+++ b/web-ui/app/js/features/features.js
@@ -34,8 +34,8 @@ define(['helpers/monitored_ajax'], function(monitoredAjax) {
var features;
monitoredAjax(this, '/features', {
async: false,
- success: function (results){
- features = results;
+ success: function (results) {
+ features = results;
},
error: function () {
console.error('Could not load feature toggles');
diff --git a/web-ui/app/js/mail_view/data/attachment_list.js b/web-ui/app/js/mail_view/data/attachment_list.js
new file mode 100644
index 00000000..af48b059
--- /dev/null
+++ b/web-ui/app/js/mail_view/data/attachment_list.js
@@ -0,0 +1,40 @@
+/*
+ * 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(
+ [
+ 'page/events'
+ ],
+
+ function (events) {
+ 'use strict';
+
+ function attachmentList() {
+ this.defaultAttrs({
+ attachments: []
+ });
+
+ this.addAttachment = function (event, data) {
+ this.attr.attachments.push(data);
+ };
+
+ this.after('initialize', function () {
+ this.on(document, events.mail.uploadedAttachment, this.addAttachment);
+ });
+ }
+ return attachmentList;
+ }); \ No newline at end of file
diff --git a/web-ui/app/js/mail_view/data/mail_builder.js b/web-ui/app/js/mail_view/data/mail_builder.js
index 74e38057..7a478dd8 100644
--- a/web-ui/app/js/mail_view/data/mail_builder.js
+++ b/web-ui/app/js/mail_view/data/mail_builder.js
@@ -16,79 +16,87 @@
*/
define(['services/model/mail'], function (mailModel) {
- 'use strict';
+ 'use strict';
- var mail;
+ var mail;
- function recipients(mail, place, v) {
- if (v !== '' && !_.isUndefined(v)) {
- if(_.isArray(v)) {
- mail[place] = v;
- } else {
- mail[place] = v.split(' ');
- }
- } else {
- mail[place] = [];
+ function recipients(mail, place, v) {
+ if (v !== '' && !_.isUndefined(v)) {
+ if (_.isArray(v)) {
+ mail[place] = v;
+ } else {
+ mail[place] = v.split(' ');
+ }
+ } else {
+ mail[place] = [];
+ }
}
- }
- return {
- newMail: function(ident) {
- ident = _.isUndefined(ident) ? '' : ident;
+ return {
+ newMail: function (ident) {
+ ident = _.isUndefined(ident) ? '' : ident;
- mail = {
- header: {
- to: [],
- cc: [],
- bcc: [],
- from: undefined,
- subject: ''
+ mail = {
+ header: {
+ to: [],
+ cc: [],
+ bcc: [],
+ from: undefined,
+ subject: ''
+ },
+ tags: [],
+ body: '',
+ attachments: [],
+ ident: ident
+ };
+ return this;
},
- tags: [],
- body: '',
- ident: ident
- };
- return this;
- },
- subject: function (subject) {
- mail.header.subject = subject;
- return this;
- },
+ subject: function (subject) {
+ mail.header.subject = subject;
+ return this;
+ },
- body: function(body) {
- mail.body = body;
- return this;
- },
+ body: function (body) {
+ mail.body = body;
+ return this;
+ },
- to: function (to) {
- recipients(mail.header, 'to', to);
- return this;
- },
+ to: function (to) {
+ recipients(mail.header, 'to', to);
+ return this;
+ },
+
+ cc: function (cc) {
+ recipients(mail.header, 'cc', cc);
+ return this;
+ },
- cc: function (cc) {
- recipients(mail.header, 'cc', cc);
- return this;
- },
+ bcc: function (bcc) {
+ recipients(mail.header, 'bcc', bcc);
+ return this;
+ },
- bcc: function (bcc) {
- recipients(mail.header, 'bcc', bcc);
- return this;
- },
+ header: function (name, value) {
+ mail.header[name] = value;
+ return this;
+ },
- header: function(name, value) {
- mail.header[name] = value;
- return this;
- },
+ tag: function (tag) {
+ if (_.isUndefined(tag)) {
+ tag = 'drafts';
+ }
+ mail.tags.push(tag);
+ return this;
+ },
- tag: function(tag) {
- if(_.isUndefined(tag)) { tag = 'drafts'; }
- mail.tags.push(tag);
- return this;
- },
+ attachment: function (attachmentList) {
+ mail.attachments = attachmentList;
+ return this;
+ },
- build: function() {
- return mailModel.create(mail);
- }
- };
+ build: function () {
+ return mailModel.create(mail);
+ }
+ };
});
diff --git a/web-ui/app/js/mail_view/ui/attachment.js b/web-ui/app/js/mail_view/ui/attachment.js
new file mode 100644
index 00000000..f57fea5b
--- /dev/null
+++ b/web-ui/app/js/mail_view/ui/attachment.js
@@ -0,0 +1,68 @@
+/*
+ * 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',
+ 'page/events',
+ 'features'
+ ],
+
+ function (defineComponent, events, features) {
+ 'use strict';
+
+ return defineComponent(function () {
+ this.render = function () {
+ this.$node.html('<i class="fa fa-paperclip fa-2x"></i>');
+ };
+
+ function humanReadable(bytes) {
+ var e = Math.floor(Math.log(bytes) / Math.log(1024));
+ return (bytes / Math.pow(1024, e)).toFixed(2) + ' ' + ' KMGTP'.charAt(e) + 'b';
+ }
+
+ function addJqueryFileUploadConfig(on) {
+ var url = '/attachment';
+ $('#fileupload').fileupload({
+ url: url,
+ dataType: 'json',
+ done: function (e, response) {
+ var data = response.result;
+ $('#files').html('<span>' + data.filename + ' (' + humanReadable(data.filesize) + ')' + '</span>');
+ on.trigger(document, events.mail.uploadedAttachment, data);
+ },
+ progressall: function (e, data) {
+ var progress = parseInt(data.loaded / data.total * 100, 10);
+ $('#progress .progress-bar').css('width', progress + '%');
+ }
+ });
+ }
+
+ this.upload = function () {
+ addJqueryFileUploadConfig(this);
+ $('#fileupload').click();
+ };
+
+ this.after('initialize', function () {
+ if (features.isEnabled('attachment')) {
+ this.render();
+ }
+ this.on(this.$node, 'click', this.upload);
+ });
+
+ });
+ });
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 dcc8fd76..48a7c23f 100644
--- a/web-ui/app/js/mail_view/ui/compose_box.js
+++ b/web-ui/app/js/mail_view/ui/compose_box.js
@@ -20,13 +20,14 @@ define(
'views/templates',
'mixins/with_mail_edit_base',
'page/events',
- 'mail_view/data/mail_builder'
+ 'mail_view/data/mail_builder',
+ 'mail_view/data/attachment_list'
],
- function (defineComponent, templates, withMailEditBase, events, mailBuilder) {
+ function (defineComponent, templates, withMailEditBase, events, mailBuilder, attachmentList) {
'use strict';
- return defineComponent(composeBox, withMailEditBase);
+ return defineComponent(composeBox, withMailEditBase, attachmentList);
function composeBox() {
@@ -49,6 +50,7 @@ define(
.cc(this.attr.recipientValues.cc)
.bcc(this.attr.recipientValues.bcc)
.body(this.select('bodyBox').val())
+ .attachment(this.attr.attachments)
.tag(tag);
};
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 a1fa6b09..1b5e8c52 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/attachment',
'flight/lib/utils'
],
- function(viewHelper, Recipients, DraftSaveStatus, events, i18n, SendButton, utils) {
+ function(viewHelper, Recipients, DraftSaveStatus, events, i18n, SendButton, Attachment, utils) {
'use strict';
function withMailEditBase() {
@@ -33,6 +34,7 @@ define(
this.defaultAttrs({
bodyBox: '#text-box',
sendButton: '#send-button',
+ attachmentButton: '#attachment-button',
cancelButton: '#cancel-button',
trashButton: '#trash-button',
toArea: '#recipients-to-area',
@@ -93,6 +95,7 @@ define(
this.on(this.select('trashButton'), 'click', this.discardMail);
SendButton.attachTo(this.select('sendButton'));
+ Attachment.attachTo(this.select('attachmentButton'));
this.warnSendButtonOfRecipients();
};
diff --git a/web-ui/app/js/page/events.js b/web-ui/app/js/page/events.js
index 4ed25185..4d817b91 100644
--- a/web-ui/app/js/page/events.js
+++ b/web-ui/app/js/page/events.js
@@ -142,7 +142,8 @@ define(function () {
tags: {
update: 'mail:tags:update',
updated: 'mail:tags:updated'
- }
+ },
+ uploadedAttachment: 'mail:uploaded:attachment'
},
mails: {
available: 'mails:available',
diff --git a/web-ui/app/scss/styles.scss b/web-ui/app/scss/styles.scss
index 431f6292..dff5a472 100644
--- a/web-ui/app/scss/styles.scss
+++ b/web-ui/app/scss/styles.scss
@@ -883,4 +883,8 @@ div.side-nav-bottom {
}
}
+#compose-box span#attachment-button{
+ cursor: pointer;
+}
+
@import "mascot.scss";
diff --git a/web-ui/app/templates/compose/compose_box.hbs b/web-ui/app/templates/compose/compose_box.hbs
index 6a703820..ea14e4fe 100644
--- a/web-ui/app/templates/compose/compose_box.hbs
+++ b/web-ui/app/templates/compose/compose_box.hbs
@@ -7,20 +7,38 @@
</div>
<button class="close-mail-button">
- <i class="fa fa-times"></i>
+ <i class="fa fa-times"></i>
</button>
<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="4"/>
+ <label class="floatlabel" for="subject">Subject</label>
+ <input class="floatlabel" name="subject" type="text" id="subject" value="{{subject}}" placeholder="{{t 'Subject'}}"
+ tabindex="4"/>
</div>
<div class="floatlabel">
- <label class="floatlabel" for="body">Body</label>
- <textarea class="floatlabel" name="body" id="text-box" placeholder="{{t 'Body'}}" tabindex="5">{{body}}</textarea>
+ <label class="floatlabel" for="body">Body</label>
+ <textarea class="floatlabel" name="body" id="text-box" placeholder="{{t 'Body'}}" tabindex="5">{{body}}</textarea>
</div>
<div class="buttons-group columns">
- <button id="send-button" tabindex="6"><i class="fa fa-send"></i></button>
- <button id="trash-button" tabindex="7">{{t 'trash-button'}}<i class="fa fa-trash-o"></i></button>
- <div id="draft-save-status"></div>
+ <span class="btn btn-success fileinput-button">
+ <!-- The file input field used as target for the file upload widget -->
+ <input id="fileupload" type="file" name="attachment">
+ </span>
+ <br>
+ <br>
+ <!-- The global progress bar -->
+ <div id="progress" class="progress">
+ <div class="progress-bar progress-bar-success"></div>
+ </div>
+ <!-- The container for the uploaded files -->
+ <div id="files" class="files"></div>
+ <br>
+</div>
+
+<div class="buttons-group columns">
+ <button id="send-button" tabindex="6"><i class="fa fa-send"></i></button>
+ <span id="attachment-button" tabindex="6"></span>
+ <button id="trash-button" tabindex="7">{{t 'trash-button'}}<i class="fa fa-trash-o"></i></button>
+ <div id="draft-save-status"></div>
</div>
diff --git a/web-ui/bower.json b/web-ui/bower.json
index 9d7a50c5..45832b8a 100644
--- a/web-ui/bower.json
+++ b/web-ui/bower.json
@@ -13,7 +13,9 @@
"typeahead.js": "~0.10.5",
"jasmine-flight": "~3.0.0",
"utf8": "~2.0.0",
- "modernizr": "~2.8.3"
+ "modernizr": "~2.8.3",
+ "jquery-file-upload": "~9.11.2",
+ "jquery-ui": "~1.11.4"
},
"devDependencies": {
"handlebars": "2.0.0",
diff --git a/web-ui/karma.conf.js b/web-ui/karma.conf.js
index 0742f3a7..a59b1d4f 100644
--- a/web-ui/karma.conf.js
+++ b/web-ui/karma.conf.js
@@ -19,6 +19,8 @@ module.exports = function (config) {
// loaded without require
'app/bower_components/lodash/dist/lodash.js',
'app/bower_components/jquery/dist/jquery.js',
+ 'app/bower_components/jquery-ui/jquery-ui.min.js',
+ 'app/bower_components/jquery-file-upload/js/jquery.fileupload.js',
'app/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
'app/bower_components/jasmine-flight/lib/jasmine-flight.js',
'app/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
diff --git a/web-ui/test/spec/mail_view/data/attachment_list.spec.js b/web-ui/test/spec/mail_view/data/attachment_list.spec.js
new file mode 100644
index 00000000..74c1dea7
--- /dev/null
+++ b/web-ui/test/spec/mail_view/data/attachment_list.spec.js
@@ -0,0 +1,21 @@
+describeMixin('mail_view/data/attachment_list', function () {
+ 'use strict';
+
+ describe('initialization', function() {
+ beforeEach(function(){
+ this.setupComponent();
+ });
+
+ it('should add attachment to the list based on uploadedAttachment event', function () {
+ var stubAttachment = {attachment_id: 'faked'};
+ $(document).trigger(Pixelated.events.mail.uploadedAttachment, stubAttachment);
+ expect(this.component.attr.attachments).toEqual([stubAttachment]);
+
+ var anotherStubAttachment = {attachment_id: 'faked 2'};
+ $(document).trigger(Pixelated.events.mail.uploadedAttachment, anotherStubAttachment);
+ expect(this.component.attr.attachments).toEqual([stubAttachment, anotherStubAttachment]);
+ });
+
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/data/mail_builder.spec.js b/web-ui/test/spec/mail_view/data/mail_builder.spec.js
index 7f69098f..7ba860f4 100644
--- a/web-ui/test/spec/mail_view/data/mail_builder.spec.js
+++ b/web-ui/test/spec/mail_view/data/mail_builder.spec.js
@@ -106,5 +106,13 @@ define(['mail_view/data/mail_builder'], function (mailBuilder) {
expect(mail.tags).toContain('tag1');
});
+
+ it('sets attachments', function() {
+ var mail = mailBuilder.newMail()
+ .attachment(['faked attachment list'])
+ .build();
+
+ expect(mail.attachments).toEqual(['faked attachment list']);
+ });
});
});
diff --git a/web-ui/test/spec/mail_view/ui/attachment.spec.js b/web-ui/test/spec/mail_view/ui/attachment.spec.js
index 5d14f860..bbea2f55 100644
--- a/web-ui/test/spec/mail_view/ui/attachment.spec.js
+++ b/web-ui/test/spec/mail_view/ui/attachment.spec.js
@@ -1,3 +1,21 @@
-/**
- * Created by mnandri on 12/15/15.
- */
+describeComponent('mail_view/ui/attachment', function () {
+ 'use strict';
+
+ describe('attachment', function () {
+ beforeEach(function () {
+ Pixelated.mockBloodhound();
+ this.setupComponent();
+ });
+
+ it('render attachment button if feature enabled', function () {
+ expect(this.$node.html()).toMatch('<i class="fa fa-paperclip fa-2x"></i>');
+ });
+
+ xit('uploads attachment on click', function () {
+ var fileUploads = spyOn($, 'fileupload');
+ this.$node.click();
+ expect(fileUploads).toHaveBeenCalled();
+ });
+
+ });
+});