diff options
Diffstat (limited to 'web-ui/app/js/mail_list')
-rw-r--r-- | web-ui/app/js/mail_list/domain/refresher.js | 25 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_item_factory.js | 49 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_items/draft_item.js | 55 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js | 97 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_items/mail_item.js | 63 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_items/sent_item.js | 62 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_list.js | 185 |
7 files changed, 536 insertions, 0 deletions
diff --git a/web-ui/app/js/mail_list/domain/refresher.js b/web-ui/app/js/mail_list/domain/refresher.js new file mode 100644 index 00000000..f1fe504d --- /dev/null +++ b/web-ui/app/js/mail_list/domain/refresher.js @@ -0,0 +1,25 @@ +define(['flight/lib/component', 'page/events'], function(defineComponent, events) { + 'use strict'; + + return defineComponent(refresher); + + function refresher() { + this.defaultAttrs({ + interval: 20000 + }); + + this.setupRefresher = function() { + setTimeout(this.doRefresh.bind(this), this.attr.interval); + }; + + this.doRefresh = function() { + this.trigger(document, events.ui.mails.refresh); + this.setupRefresher(); + }; + + this.after('initialize', function () { + this.setupRefresher(); + }); + } + } +); 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 new file mode 100644 index 00000000..0a20e58c --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_item_factory.js @@ -0,0 +1,49 @@ +'use strict'; + +define( + [ + 'mail_list/ui/mail_items/generic_mail_item', + 'mail_list/ui/mail_items/draft_item', + 'mail_list/ui/mail_items/sent_item' + ], + function (GenericMailItem, DraftItem, SentItem) { + + var MAIL_ITEM_TYPE = { + 'drafts': DraftItem, + 'sent': SentItem + }; + + var createAndAttach = function (nodeToAttachTo, mail, currentMailIdent, currentTag, isChecked) { + var mailItemContainer = $('<li>', { id: 'mail-' + mail.ident}); + nodeToAttachTo.append(mailItemContainer); + + var mailToCreate; + if(currentTag === 'all'){ + mailToCreate = detectMailType(mail); + } else { + mailToCreate = MAIL_ITEM_TYPE[currentTag] || GenericMailItem; + } + mailToCreate.attachTo(mailItemContainer, { + mail: mail, + selected: mail.ident === currentMailIdent, + tag: currentTag, + isChecked: isChecked + }); + + }; + + var detectMailType = function(mail) { + if(_.include(mail.tags, 'drafts')) { + return MAIL_ITEM_TYPE['drafts']; + } else if(_.include(mail.tags, 'sent')) { + return MAIL_ITEM_TYPE['sent']; + } else { + return GenericMailItem; + }; + }; + + return { + createAndAttach: createAndAttach + }; + } +); diff --git a/web-ui/app/js/mail_list/ui/mail_items/draft_item.js b/web-ui/app/js/mail_list/ui/mail_items/draft_item.js new file mode 100644 index 00000000..7a93af21 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/draft_item.js @@ -0,0 +1,55 @@ +/*global _ */ + +define( + [ + 'flight/lib/component', + 'views/templates', + 'helpers/view_helper', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, templates, viewHelpers, mailItem, events) { + 'use strict'; + + return defineComponent(draftItem, mailItem); + + function draftItem() { + function isOpeningOnANewTab(ev) { + return ev.metaKey || ev.ctrlKey || ev.which === 2; + } + + this.triggerOpenMail = function (ev) { + if (isOpeningOnANewTab(ev)) { + return; + } + this.trigger(document, events.dispatchers.rightPane.openDraft, { ident: this.attr.ident }); + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + this.render = function () { + var mailItemHtml = templates.mails.sent(this.attr); + this.$node.html(mailItemHtml); + this.$node.addClass(this.attr.statuses); + if(this.attr.selected) { this.select(); } + this.on(this.$node.find('a'), 'click', this.triggerOpenMail); + }; + + this.after('initialize', function () { + this.initializeAttributes(); + this.render(); + this.attachListeners(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.unselect); + this.on(document, events.ui.mail.updateSelected, this.updateSelected); + this.on(document, events.mails.teardown, this.teardown); + }); + } + } +); diff --git a/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js new file mode 100644 index 00000000..0f9157a7 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js @@ -0,0 +1,97 @@ +/*global _ */ + +define( + [ + 'flight/lib/component', + 'views/templates', + 'helpers/view_helper', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, templates, viewHelpers, mailItem, events) { + 'use strict'; + + return defineComponent(genericMailItem, mailItem); + + function genericMailItem() { + this.status = { + READ: 'read' + }; + + function isOpeningOnANewTab(ev) { + return ev.metaKey || ev.ctrlKey || ev.which === 2; + } + + this.triggerOpenMail = function (ev) { + if (isOpeningOnANewTab(ev)) { + updateMailStatusToRead.call(this); + return; + } + this.trigger(document, events.ui.mail.open, { ident: this.attr.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + function updateMailStatusToRead() { + if (!_.contains(this.attr.mail.status, this.status.READ)) { + this.trigger(document, events.mail.read, { ident: this.attr.ident, tags: this.attr.mail.tags }); + this.attr.mail.status.push(this.status.READ); + this.$node.addClass(viewHelpers.formatStatusClasses(this.attr.mail.status)); + } + } + + this.openMail = function (ev, data) { + if (data.ident !== this.attr.ident) { + return; + } + updateMailStatusToRead.call(this); + + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.ident }); + }; + + this.updateTags = function(ev, data) { + if(data.ident === this.attr.ident){ + this.attr.tags = data.tags; + if(!_.contains(this.attr.tags, this.attr.tag)) { + this.teardown(); + } else { + this.render(); + } + } + }; + + this.deleteMail = function(ev, data) { + if(data.mail.ident === this.attr.ident){ + this.teardown(); + } + }; + + this.render = function () { + this.attr.tagsForListView = _.without(this.attr.tags, this.attr.tag); + var mailItemHtml = templates.mails.single(this.attr); + this.$node.html(mailItemHtml); + this.$node.addClass(this.attr.statuses); + this.attr.selected && this.select(); + this.on(this.$node.find('a'), 'click', this.triggerOpenMail); + }; + + this.after('initialize', function () { + this.initializeAttributes(); + this.render(); + this.attachListeners(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.unselect); + this.on(document, events.ui.mail.open, this.openMail); + this.on(document, events.ui.mail.updateSelected, this.updateSelected); + this.on(document, events.mails.teardown, this.teardown); + this.on(document, events.mail.tags.update, this.updateTags); + this.on(document, events.mail.delete, this.deleteMail); + }); + } + } +); diff --git a/web-ui/app/js/mail_list/ui/mail_items/mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js new file mode 100644 index 00000000..c0628984 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js @@ -0,0 +1,63 @@ +'use strict'; + +define( + ['helpers/view_helper', + 'page/events'], function (viewHelper, events) { + + function mailItem() { + this.updateSelected = function (ev, data) { + if(data.ident === this.attr.ident) { this.select(); } + else { this.unselect(); } + }; + + this.formattedDate = function (date) { + return viewHelper.getFormattedDate(new Date(date)); + }; + + this.select = function () { + this.$node.addClass('selected'); + }; + + this.unselect = function () { + this.$node.removeClass('selected'); + }; + + this.triggerMailChecked = function (ev, data) { + var eventToTrigger = ev.target.checked ? events.ui.mail.checked : events.ui.mail.unchecked; + this.trigger(document, eventToTrigger, { mail: this.attr.mail}); + }; + + this.checkboxElement = function () { + return this.$node.find('input[type=checkbox]'); + }; + + this.checkCheckbox = function () { + this.checkboxElement().prop('checked', true); + this.triggerMailChecked({'target': {'checked': true}}); + }; + + this.uncheckCheckbox = function () { + this.checkboxElement().prop('checked', false); + this.triggerMailChecked({'target': {'checked': false}}); + }; + + this.initializeAttributes = function () { + var mail = this.attr.mail; + this.attr.ident = mail.ident; + this.attr.header = mail.header; + this.attr.ident = mail.ident; + this.attr.statuses = viewHelper.formatStatusClasses(mail.status); + this.attr.tags = mail.tags; + this.attr.header.formattedDate = this.formattedDate(mail.header.date); + }; + + this.attachListeners = function () { + this.on(this.$node.find('input[type=checkbox]'), 'change', this.triggerMailChecked); + this.on(document, events.ui.mails.cleanSelected, this.unselect); + this.on(document, events.ui.mails.uncheckAll, this.uncheckCheckbox); + this.on(document, events.ui.mails.checkAll, this.checkCheckbox); + }; + } + + return mailItem; +}); diff --git a/web-ui/app/js/mail_list/ui/mail_items/sent_item.js b/web-ui/app/js/mail_list/ui/mail_items/sent_item.js new file mode 100644 index 00000000..8cdb8dd4 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/sent_item.js @@ -0,0 +1,62 @@ +/*global _ */ + +define( + [ + 'flight/lib/component', + 'views/templates', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, templates, mailItem, events) { + 'use strict'; + + return defineComponent(sentItem, mailItem); + + function sentItem() { + function isOpeningOnANewTab(ev) { + return ev.metaKey || ev.ctrlKey || ev.which == 2; + } + + this.triggerOpenMail = function (ev) { + if (isOpeningOnANewTab(ev)) { + return; + } + this.trigger(document, events.ui.mail.open, { ident: this.attr.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + this.openMail = function (ev, data) { + if (data.ident !== this.attr.ident) { + return; + } + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.ident }); + }; + + this.render = function () { + this.attr.tagsForListView = _.without(this.attr.tags, this.attr.tag); + var mailItemHtml = templates.mails.sent(this.attr); + this.$node.html(mailItemHtml); + this.$node.addClass(this.attr.statuses); + this.attr.selected && this.select(); + this.on(this.$node.find('a'), 'click', this.triggerOpenMail); + }; + + this.after('initialize', function () { + this.initializeAttributes(); + this.render(); + this.attachListeners(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.unselect); + this.on(document, events.ui.mail.open, this.openMail); + this.on(document, events.ui.mail.updateSelected, this.updateSelected); + this.on(document, events.mails.teardown, this.teardown); + }); + } + } +); diff --git a/web-ui/app/js/mail_list/ui/mail_list.js b/web-ui/app/js/mail_list/ui/mail_list.js new file mode 100644 index 00000000..a12c365d --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_list.js @@ -0,0 +1,185 @@ +/*global _ */ + +define( + [ + 'flight/lib/component', + 'flight/lib/utils', + 'mail_list/ui/mail_item_factory', + 'page/router/url_params', + 'page/events' + ], + + function (defineComponent, utils, MailItemFactory, urlParams, events) { + 'use strict'; + + return defineComponent(mailList); + + function mailList() { + var self; + + var openMailEventFor = function (tag) { + return tag === 'drafts' ? events.dispatchers.rightPane.openDraft : events.ui.mail.open; + }; + + this.defaultAttrs({ + mail: '.mail', + currentMailIdent: '', + urlParams: urlParams, + initialized: false, + checkedMails: {} + }); + + function appendMail(mail) { + var isChecked = mail.ident in self.attr.checkedMails; + MailItemFactory.createAndAttach(self.$node, mail, self.attr.currentMailIdent, self.attr.currentTag, isChecked); + } + + function resetMailList() { + self.trigger(document, events.mails.teardown); + self.$node.empty(); + } + + function triggerMailOpenForPopState(data) { + if(data.mailIdent) { + self.trigger(document, openMailEventFor(data.tag), { ident: data.mailIdent }); + } + } + + function shouldSelectEmailFromUrlMailIdent() { + return self.attr.urlParams.hasMailIdent(); + } + + function selectMailBasedOnUrlMailIdent() { + var mailIdent = self.attr.urlParams.getMailIdent(); + self.trigger(document, openMailEventFor(self.attr.currentTag), { ident: mailIdent }); + self.trigger(document, events.router.pushState, { tag: self.attr.currentTag, mailIdent: mailIdent }); + } + + function updateCurrentTagAndMail(data) { + if (data.ident) { + self.attr.currentMailIdent = data.ident; + } + self.attr.currentTag = data.tag || self.attr.currentTag; + } + + function renderMails(mails) { + _.each(mails, appendMail); + self.trigger(document, events.search.highlightResults, {where: '#mail-list'}); + self.trigger(document, events.search.highlightResults, {where: '.bodyArea'}); + self.trigger(document, events.search.highlightResults, {where: '.subjectArea'}); + self.trigger(document, events.search.highlightResults, {where: '.msg-header .recipients'}); + + } + + this.triggerScrollReset = function() { + this.trigger(document, events.dispatchers.middlePane.resetScroll); + }; + + this.showMails = function (event, data) { + updateCurrentTagAndMail(data); + this.refreshMailList(null, data); + this.triggerScrollReset(); + triggerMailOpenForPopState(data); + this.openMailFromUrl(); + }; + + this.refreshMailList = function (ev, data) { + resetMailList(); + renderMails(data.mails); + }; + + this.updateSelected = function (ev, data) { + if(data.ident !== this.attr.currentMailIdent){ + this.uncheckCurrentMail(); + this.attr.currentMailIdent = data.ident; + } + this.checkCurrentMail(); + }; + + this.checkCurrentMail = function() { + $('#mail-'+this.attr.currentMailIdent+' input:checkbox') + .attr('checked', true) + .trigger('change'); + }; + + this.uncheckCurrentMail = function() { + $('#mail-'+this.attr.currentMailIdent+' input:checkbox') + .attr('checked', false) + .trigger('change'); + }; + + this.cleanSelected = function () { + this.attr.currentMailIdent = ''; + }; + + this.respondWithCheckedMails = function (ev, caller) { + this.trigger(caller, events.ui.mail.hereChecked, { checkedMails : this.attr.checkedMails }); + }; + + this.updateCheckAllCheckbox = function () { + if (_.keys(this.attr.checkedMails).length > 0) { + this.trigger(document, events.ui.mails.hasMailsChecked, true); + } else { + this.trigger(document, events.ui.mails.hasMailsChecked, false); + } + }; + + this.addToSelectedMails = function (ev, data) { + this.attr.checkedMails[data.mail.ident] = data.mail; + this.updateCheckAllCheckbox(); + }; + + this.removeFromSelectedMails = function (ev, data) { + if (data.mails) { + _.each(data.mails, function(mail) { + delete this.attr.checkedMails[mail.ident]; + }, this); + } else { + delete this.attr.checkedMails[data.mail.ident]; + } + this.updateCheckAllCheckbox(); + }; + + this.refreshWithScroll = function () { + this.trigger(document, events.ui.mails.refresh); + this.triggerScrollReset(); + }; + + this.refreshAfterSaveDraft = function () { + if(this.attr.currentTag === 'drafts') { + this.refreshWithScroll(); + } + }; + + this.refreshAfterMailSent = function () { + if(this.attr.currentTag === 'drafts' || this.attr.currentTag === 'sent') { + this.refreshWithScroll(); + } + }; + + this.after('initialize', function () { + self = this; + + this.on(document, events.ui.mails.cleanSelected, this.cleanSelected); + + this.on(document, events.mails.available, this.showMails); + this.on(document, events.mails.availableForRefresh, this.refreshMailList); + + this.on(document, events.mail.draftSaved, this.refreshAfterSaveDraft); + this.on(document, events.mail.sent, this.refreshAfterMailSent); + + this.on(document, events.ui.mail.updateSelected, this.updateSelected); + this.on(document, events.ui.mail.wantChecked, this.respondWithCheckedMails); + this.on(document, events.ui.mail.checked, this.addToSelectedMails); + this.on(document, events.ui.mail.unchecked, this.removeFromSelectedMails); + + this.openMailFromUrl = utils.once(function () { + if(shouldSelectEmailFromUrlMailIdent()) { + selectMailBasedOnUrlMailIdent(); + } + }); + + }); + } + } +); |