diff options
Diffstat (limited to 'web-ui/app/js/mail_list')
-rw-r--r-- | web-ui/app/js/mail_list/domain/refresher.js | 43 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_item_factory.js | 59 | ||||
-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 | 88 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_items/sent_item.js | 61 | ||||
-rw-r--r-- | web-ui/app/js/mail_list/ui/mail_list.js | 182 |
7 files changed, 585 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..38c9cde5 --- /dev/null +++ b/web-ui/app/js/mail_list/domain/refresher.js @@ -0,0 +1,43 @@ +/* + * 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/>. + */ +define(['flight/lib/component', 'page/events', 'features'], function(defineComponent, events, features) { + '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 () { + if (features.isAutoRefreshEnabled()) { + 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..7205d35c --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_item_factory.js @@ -0,0 +1,59 @@ +/* + * 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/>. + */ + +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) { + 'use strict'; + + var MAIL_ITEM_TYPE = { + 'drafts': DraftItem, + 'sent': SentItem, + 'trash': GenericMailItem + }; + + var TEMPLATE_TYPE = { + 'drafts': 'draft', + 'sent': 'sent', + 'trash': 'trash' + }; + + var createAndAttach = function (nodeToAttachTo, mail, currentMailIdent, currentTag, isChecked) { + var mailItemContainer = $('<li>', { id: 'mail-' + mail.ident}); + nodeToAttachTo.append(mailItemContainer); + + mail.currentTag = currentTag; + var mailToCreate = MAIL_ITEM_TYPE[mail.mailbox] || GenericMailItem; + mailToCreate.attachTo(mailItemContainer, { + mail: mail, + selected: mail.ident === currentMailIdent, + tag: currentTag, + isChecked: isChecked, + templateType: TEMPLATE_TYPE[mail.mailbox] || 'single' + }); + + }; + + 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..57fbafd5 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/draft_item.js @@ -0,0 +1,55 @@ +/* + * 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/>. + */ + +define( + [ + 'flight/lib/component', + 'helpers/view_helper', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, viewHelpers, mailItem, events) { + 'use strict'; + + return defineComponent(draftItem, mailItem); + + function draftItem() { + this.triggerOpenMail = function (ev) { + if (this.isOpeningOnANewTab(ev)) { + return; + } + this.trigger(document, events.dispatchers.rightPane.openDraft, { ident: this.attr.mail.ident }); + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.mail.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.mail.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + this.after('initialize', function () { + this.render(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.doUnselect); + 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..939f7e1b --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js @@ -0,0 +1,97 @@ +/* + * 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/>. + */ + +define( + [ + 'flight/lib/component', + 'helpers/view_helper', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, viewHelpers, mailItem, events) { + 'use strict'; + + return defineComponent(genericMailItem, mailItem); + + function genericMailItem() { + this.status = { + READ: 'read' + }; + + this.triggerOpenMail = function (ev) { + if (this.isOpeningOnANewTab(ev)) { + updateMailStatusToRead.call(this); + return; + } + this.trigger(document, events.ui.mail.open, { ident: this.attr.mail.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.mail.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + function updateMailStatusToRead() { + if (!_.contains(this.attr.mail.status, this.status.READ)) { + var mail_read_data = { ident: this.attr.mail.ident, tags: this.attr.mail.tags, mailbox: this.attr.mail.mailbox }; + this.trigger(document, events.mail.read, mail_read_data); + 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.mail.ident) { + return; + } + updateMailStatusToRead.call(this); + + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.mail.ident }); + }; + + this.updateTags = function(ev, data) { + if(data.ident === this.attr.mail.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.mail.ident){ + this.teardown(); + } + }; + + this.after('initialize', function () { + this.render(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.doUnselect); + 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..be664289 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js @@ -0,0 +1,88 @@ +/* + * 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/>. + */ + +define( + [ + 'helpers/view_helper', + 'views/templates', + 'page/events' + ], + function (viewHelper, templates, events) { + + 'use strict'; + function mailItem() { + this.updateSelected = function (ev, data) { + if (data.ident === this.attr.mail.ident) { this.doSelect(); } + else { this.doUnselect(); } + }; + + this.isOpeningOnANewTab = function (ev) { + return ev.metaKey || ev.ctrlKey || ev.which === 2; + }; + + this.doSelect = function () { + this.$node.addClass('selected'); + }; + + this.doUnselect = function () { + this.$node.removeClass('selected'); + }; + + this.doMailChecked = function (ev) { + if (ev.target.checked) { + this.checkCheckbox(); + } else { + this.uncheckCheckbox(); + } + }; + + this.checkboxElement = function () { + return this.$node.find('input[type=checkbox]'); + }; + + this.checkCheckbox = function () { + this.checkboxElement().prop('checked', true); + this.trigger(document, events.ui.mail.checked, { mail: this.attr.mail}); + }; + + this.uncheckCheckbox = function () { + this.checkboxElement().prop('checked', false); + this.trigger(document, events.ui.mail.unchecked, { mail: this.attr.mail}); + }; + + this.render = function () { + this.attr.mail.tagsForListView = _.without(this.attr.mail.tags, this.attr.tag); + var mailItemHtml = templates.mails[this.attr.templateType](this.attr.mail); + this.$node.html(mailItemHtml); + this.$node.addClass("mail-list-entry"); + this.$node.addClass(viewHelper.formatStatusClasses(this.attr.mail.status)); + if (this.attr.selected) { this.doSelect(); } + this.on(this.$node.find('a'), 'click', this.triggerOpenMail); + }; + + this.after('initialize', function () { + this.on(this.$node.find('input[type=checkbox]'), 'change', this.doMailChecked); + this.on(document, events.ui.mails.cleanSelected, this.doUnselect); + this.on(document, events.ui.tag.select, this.doUnselect); + this.on(document, events.ui.tag.select, this.uncheckCheckbox); + 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..9e511068 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_items/sent_item.js @@ -0,0 +1,61 @@ +/* + * 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/>. + */ + +define( + [ + 'flight/lib/component', + 'mail_list/ui/mail_items/mail_item', + 'page/events' + ], + + function (defineComponent, mailItem, events) { + 'use strict'; + + return defineComponent(sentItem, mailItem); + + function sentItem() { + this.triggerOpenMail = function (ev) { + if (this.isOpeningOnANewTab(ev)) { + return; + } + this.trigger(document, events.ui.mail.open, { ident: this.attr.mail.ident }); + this.trigger(document, events.router.pushState, { mailIdent: this.attr.mail.ident }); + ev.preventDefault(); // don't let the hashchange trigger a popstate + }; + + this.openMail = function (ev, data) { + if (data.ident !== this.attr.mail.ident) { + return; + } + this.trigger(document, events.ui.mail.updateSelected, { ident: this.attr.mail.ident }); + }; + + this.after('initialize', function () { + this.render(); + + if (this.attr.isChecked) { + this.checkCheckbox(); + } + + this.on(document, events.ui.composeBox.newMessage, this.doUnselect); + 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..af4821a8 --- /dev/null +++ b/web-ui/app/js/mail_list/ui/mail_list.js @@ -0,0 +1,182 @@ +/* + * 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/>. + */ + +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 openMailEventFor = function (tag) { + return tag === 'drafts' ? events.dispatchers.rightPane.openDraft : events.ui.mail.open; + }; + + this.defaultAttrs({ + mail: '.mail', + currentMailIdent: '', + urlParams: urlParams, + initialized: false, + checkedMails: {} + }); + + this.appendMail = function (mail) { + var isChecked = mail.ident in this.attr.checkedMails; + MailItemFactory.createAndAttach(this.$node, mail, this.attr.currentMailIdent, this.attr.currentTag, isChecked); + }; + + this.resetMailList = function () { + this.trigger(document, events.mails.teardown); + this.$node.empty(); + }; + + this.triggerMailOpenForPopState = function (data) { + if (data.mailIdent) { + this.trigger(document, openMailEventFor(data.tag), { ident: data.mailIdent }); + } + }; + + this.shouldSelectEmailFromUrlMailIdent = function () { + return this.attr.urlParams.hasMailIdent(); + }; + + this.selectMailBasedOnUrlMailIdent = function () { + var mailIdent = this.attr.urlParams.getMailIdent(); + this.trigger(document, openMailEventFor(this.attr.currentTag), { ident: mailIdent }); + this.trigger(document, events.router.pushState, { tag: this.attr.currentTag, mailIdent: mailIdent }); + }; + + this.updateCurrentTagAndMail = function (data) { + if (data.ident) { + this.attr.currentMailIdent = data.ident; + } + + this.attr.currentTag = data.tag || this.attr.currentTag; + + this.updateCheckAllCheckbox(); + }; + + this.renderMails = function (mails) { + _.each(mails, this.appendMail, this); + this.trigger(document, events.search.highlightResults, {where: '#mail-list'}); + this.trigger(document, events.search.highlightResults, {where: '.mail-read-view__header'}); + }; + + this.triggerScrollReset = function () { + this.trigger(document, events.dispatchers.middlePane.resetScroll); + }; + + this.showMails = function (event, data) { + this.updateCurrentTagAndMail(data); + this.refreshMailList(null, data); + this.triggerMailOpenForPopState(data); + this.openMailFromUrl(); + }; + + this.refreshMailList = function (ev, data) { + if (ev) { // triggered by the event, so we need to refresh the tag list + this.trigger(document, events.dispatchers.tags.refreshTagList, { skipMailListRefresh: true }); + } + this.resetMailList(); + this.renderMails(data.mails); + }; + + this.updateSelected = function (ev, data) { + if (data.ident !== this.attr.currentMailIdent) { + this.attr.currentMailIdent = data.ident; + } + }; + + this.cleanSelected = function () { + this.attr.currentMailIdent = ''; + this.triggerScrollReset(); + }; + + this.respondWithCheckedMails = function (ev, caller) { + this.trigger(caller, events.ui.mail.hereChecked, {checkedMails: this.attr.checkedMails}); + }; + + this.updateCheckAllCheckbox = function () { + this.trigger(document, events.ui.mails.hasMailsChecked, _.keys(this.attr.checkedMails).length > 0); + }; + + this.addToCheckedMails = function (ev, data) { + this.attr.checkedMails[data.mail.ident] = data.mail; + this.updateCheckAllCheckbox(); + }; + + this.removeFromCheckedMails = 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 () { + this.on(document, events.ui.mails.cleanSelected, this.cleanSelected); + this.on(document, events.ui.tag.select, 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.addToCheckedMails); + this.on(document, events.ui.mail.unchecked, this.removeFromCheckedMails); + + this.openMailFromUrl = utils.once(function () { + if (this.shouldSelectEmailFromUrlMailIdent()) { + this.selectMailBasedOnUrlMailIdent(); + } + }); + + }); + } + } +); |