diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade index 531ada257..d387de307 100644 --- a/client/components/cards/checklists.jade +++ b/client/components/cards/checklists.jade @@ -31,7 +31,7 @@ template(name="checklistDetail") .checklist-title span if canModifyCard - a.js-delete-checklist.toggle-delete-checklist-dialog {{_ "delete"}}... + a.fa.fa-navicon.checklist-details-menu.js-open-checklist-details-menu(title="{{_ 'checklistActionsPopup-title'}}") if canModifyCard h2.title.js-open-inlined-form.is-editable @@ -133,3 +133,41 @@ template(name="boardsSwimlanesAndLists") .edit-controls.clearfix button.primary.confirm.js-done {{_ 'done'}} + +template(name="checklistActionsPopup") + ul.pop-over-list + li + a.js-delete-checklist.delete-checklist + i.fa.fa-trash + | {{_ "delete"}} ... + a.js-move-checklist.move-checklist + i.fa.fa-arrow-right + | {{_ "moveChecklist"}} ... + +template(name="moveChecklistPopup") + unless currentUser.isWorker + label {{_ 'boards'}}: + select.js-select-boards(autofocus) + each boards + if $eq _id currentBoard._id + option(value="{{_id}}" selected) {{_ 'current'}} + else + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionBoardId _id}}selected{{/if}}") {{title}} + + label {{_ 'swimlanes'}}: + select.js-select-swimlanes + each swimlanes + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionSwimlaneId _id}}selected{{/if}}") {{title}} + + label {{_ 'lists'}}: + select.js-select-lists + each lists + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionListId _id}}selected{{/if}}") {{title}} + + label {{_ 'cards'}}: + select.js-select-cards + each cards + option(value="{{_id}}" selected="{{#if isMoveChecklistDialogOptionCardId _id}}selected{{/if}}") {{title}} + + .edit-controls.clearfix + button.primary.confirm.js-done {{_ 'done'}} diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js index a1e76cd34..fcb404b95 100644 --- a/client/components/cards/checklists.js +++ b/client/components/cards/checklists.js @@ -190,13 +190,7 @@ BlazeComponent.extendComponent({ return [ { ...events, - 'click .toggle-delete-checklist-dialog' : Popup.afterConfirm('checklistDelete', function () { - Popup.close(); - const checklist = this.checklist; - if (checklist && checklist._id) { - Checklists.remove(checklist._id); - } - }), + 'click .js-open-checklist-details-menu': Popup.open('checklistActions'), 'submit .js-add-checklist': this.addChecklist, 'submit .js-edit-checklist-title': this.editChecklist, 'submit .js-add-checklist-item': this.addChecklistItem, @@ -293,6 +287,23 @@ BlazeComponent.extendComponent({ } }).register('addChecklistItemForm'); +BlazeComponent.extendComponent({ + events() { + return [ + { + 'click .js-delete-checklist' : Popup.afterConfirm('checklistDelete', function () { + Popup.back(2); + const checklist = this.checklist; + if (checklist && checklist._id) { + Checklists.remove(checklist._id); + } + }), + 'click .js-move-checklist' : Popup.open('moveChecklist'), + } + ] + } +}).register('checklistActionsPopup'); + BlazeComponent.extendComponent({ onRendered() { autosize(this.$('textarea.js-edit-checklist-item')); @@ -352,3 +363,155 @@ BlazeComponent.extendComponent({ ]; }, }).register('checklistItemDetail'); + +BlazeComponent.extendComponent({ + onCreated() { + const boardId = Utils.getCurrentBoardId(); + subManager.subscribe('board', boardId, false); + // subManager.subscribe('swimlane', swimlaneId, false); + // subManager.subscribe('list', listId, false); + // subManager.subscribe('card', cardId, false); + this.selectedBoardId = new ReactiveVar(boardId); + this.selectedSwimlaneId = new ReactiveVar(''); + this.selectedListId = new ReactiveVar(''); + this.selectedCardId = new ReactiveVar(''); + this.setMoveChecklistDialogOption(boardId); + }, + + /** set the last confirmed dialog field values + * @param boardId the current board id + */ + setMoveChecklistDialogOption(boardId) { + this.moveChecklistDialogOption = { + 'boardId' : "", + 'swimlaneId' : "", + 'listId' : "", + 'cardId': "", + } + + let currentOptions = Meteor.user().getMoveChecklistDialogOptions(); + if (currentOptions && boardId && currentOptions[boardId]) { + this.moveChecklistDialogOption = currentOptions[boardId]; + } + const board = Boards.findOne(boardId); + try { + const swimlaneId = board.swimlanes().fetch()[0]._id; + this.selectedSwimlaneId.set(swimlaneId); + } catch (e) {} + + try { + const listId = board.lists().fetch()[0]; + this.selectedListId.set(listId); + } catch (e) {} + + const cardId = Utils.getCurrentCardId(); + this.selectedCardId.set(cardId); + }, + + /** returns if the board id was the last confirmed one + * @param boardId check this board id + * @return if the board id was the last confirmed one + */ + isMoveChecklistDialogOptionBoardId(boardId) { + let ret = this.moveChecklistDialogOption.boardId == boardId; + return ret; + }, + + /** returns if the swimlane id was the last confirmed one + * @param swimlaneId check this swimlane id + * @return if the swimlane id was the last confirmed one + */ + isMoveChecklistDialogOptionSwimlaneId(swimlaneId) { + let ret = this.moveChecklistDialogOption.swimlaneId == swimlaneId; + return ret; + }, + + /** returns if the list id was the last confirmed one + * @param listId check this list id + * @return if the list id was the last confirmed one + */ + isMoveChecklistDialogOptionListId(listId) { + let ret = this.moveChecklistDialogOption.listId == listId; + return ret; + }, + + /** returns if the card id was the last confirmed one + * @param cardId check this card id + * @return if the card id was the last confirmed one + */ + isMoveChecklistDialogOptionCardId(cardId) { + let ret = this.moveChecklistDialogOption.cardId == cardId; + return ret; + }, + + boards() { + return Boards.find( + { + archived: false, + 'members.userId': Meteor.userId(), + _id: { $ne: Meteor.user().getTemplatesBoardId() }, + }, + { + sort: { sort: 1 }, + }, + ); + }, + + swimlanes() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.swimlanes(); + }, + + lists() { + const board = Boards.findOne(this.selectedBoardId.get()); + return board.lists(); + }, + + cards() { + const list = Lists.findOne(this.selectedListId.get()); + const ret = list.cards(this.selectedSwimlaneId.get()); + return ret; + }, + + events() { + return [ + { + 'click .js-done'() { + const boardSelect = this.$('.js-select-boards')[0]; + const boardId = boardSelect.options[boardSelect.selectedIndex].value; + + const listSelect = this.$('.js-select-lists')[0]; + const listId = listSelect.options[listSelect.selectedIndex].value; + + const swimlaneSelect = this.$('.js-select-swimlanes')[0]; + const swimlaneId = swimlaneSelect.options[swimlaneSelect.selectedIndex].value; + + const cardSelect = this.$('.js-select-cards')[0]; + const cardId = cardSelect.options[cardSelect.selectedIndex].value; + + const options = { + 'boardId' : boardId, + 'swimlaneId' : swimlaneId, + 'listId' : listId, + 'cardId': cardId, + } + Meteor.user().setMoveChecklistDialogOption(boardId, options); + this.data().checklist.move(cardId); + Popup.back(2); + }, + 'change .js-select-boards'(event) { + const boardId = $(event.currentTarget).val(); + subManager.subscribe('board', boardId, false); + this.setMoveChecklistDialogOption(boardId); + this.selectedBoardId.set(boardId); + }, + 'change .js-select-swimlanes'(event) { + this.selectedSwimlaneId.set($(event.currentTarget).val()); + }, + 'change .js-select-lists'(event) { + this.selectedListId.set($(event.currentTarget).val()); + }, + }, + ]; + }, +}).register('moveChecklistPopup'); diff --git a/client/components/cards/checklists.styl b/client/components/cards/checklists.styl index b78da0600..b9983e32d 100644 --- a/client/components/cards/checklists.styl +++ b/client/components/cards/checklists.styl @@ -39,9 +39,6 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item &.is-finished color: #3cb500 - .js-delete-checklist - @extends .delete-text - span.fa.checklist-handle padding-right: 20px padding-top: 3px @@ -142,3 +139,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item background: #dbdbdb color: #222 box-shadow: 0 1px 2px rgba(0,0,0,.2) + +.checklist-details-menu + float: right + padding: 6px 10px 6px 10px diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 06cee4af3..39dad5c4b 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -1138,5 +1138,8 @@ "custom-legal-notice-link-url": "Custom legal notice page URL", "acceptance_of_our_legalNotice": "By continuing, you accept our", "legalNotice": "legal notice", - "copied": "Copied!" + "copied": "Copied!", + "checklistActionsPopup-title": "Checklist Actions", + "moveChecklist": "Move Checklist", + "moveChecklistPopup-title": "Move Checklist" } diff --git a/models/checklists.js b/models/checklists.js index 30a6f2c2d..0e76d4001 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -147,6 +147,37 @@ Checklists.mutations({ setTitle(title) { return { $set: { title } }; }, + /** move the checklist to another card + * @param newCardId move the checklist to this cardId + */ + move(newCardId) { + // update every activity + Activities.find( + {checklistId: this._id} + ).forEach(activity => { + Activities.update(activity._id, { + $set: { + cardId: newCardId, + }, + }); + }); + // update every checklist-item + ChecklistItems.find( + {checklistId: this._id} + ).forEach(checklistItem => { + ChecklistItems.update(checklistItem._id, { + $set: { + cardId: newCardId, + }, + }); + }); + // update the checklist itself + return { + $set: { + cardId: newCardId, + }, + }; + }, }); if (Meteor.isServer) { diff --git a/models/users.js b/models/users.js index 98f658412..60047a17a 100644 --- a/models/users.js +++ b/models/users.js @@ -252,6 +252,38 @@ Users.attachSchema( */ type: String, }, + 'profile.moveChecklistDialog' : { + /** + * move and copy card dialog + */ + type: Object, + optional: true, + blackbox: true, + }, + 'profile.moveChecklistDialog.$.boardId': { + /** + * last selected board id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.swimlaneId': { + /** + * last selected swimlane id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.listId': { + /** + * last selected list id + */ + type: String, + }, + 'profile.moveChecklistDialog.$.cardId': { + /** + * last selected card id + */ + type: String, + }, 'profile.notifications': { /** * enabled notifications for the user @@ -653,6 +685,17 @@ Users.helpers({ return _ret; }, + /** returns all confirmed move checklist dialog field values + *