diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js index 401f4c6ef..baf7887be 100644 --- a/client/components/cards/cardDetails.js +++ b/client/components/cards/cardDetails.js @@ -388,7 +388,9 @@ BlazeComponent.extendComponent({ let card = this.data(); const listSelect = this.$('.js-select-card-details-lists')[0]; const listId = listSelect.options[listSelect.selectedIndex].value; - card.move(card.boardId, card.swimlaneId, listId, card.sort); + + const minOrder = card.getMinSort(listId, card.swimlaneId); + card.move(card.boardId, card.swimlaneId, listId, minOrder - 1); }, 'click .js-go-to-linked-card'() { Utils.goCardId(this.data().linkedId); @@ -677,21 +679,13 @@ Template.cardDetailsActionsPopup.events({ 'click .js-set-card-color': Popup.open('setCardColor'), 'click .js-move-card-to-top'(event) { event.preventDefault(); - const minOrder = _.min( - this.list() - .cardsUnfiltered(this.swimlaneId) - .map((c) => c.sort), - ); + const minOrder = this.getMinSort(); this.move(this.boardId, this.swimlaneId, this.listId, minOrder - 1); Popup.back(); }, 'click .js-move-card-to-bottom'(event) { event.preventDefault(); - const maxOrder = _.max( - this.list() - .cardsUnfiltered(this.swimlaneId) - .map((c) => c.sort), - ); + const maxOrder = this.getMaxSort(); this.move(this.boardId, this.swimlaneId, this.listId, maxOrder + 1); Popup.back(); }, @@ -836,7 +830,9 @@ Template.moveCardPopup.events({ const listId = lSelect.options[lSelect.selectedIndex].value; const slSelect = $('.js-select-swimlanes')[0]; const swimlaneId = slSelect.options[slSelect.selectedIndex].value; - card.move(boardId, swimlaneId, listId, 0); + + const minOrder = card.getMinSort(listId, swimlaneId); + card.move(boardId, swimlaneId, listId, minOrder - 1); // set new id's to card object in case the card is moved to top by the comment "moveCard" after this command (.js-move-card) this.boardId = boardId; @@ -964,8 +960,10 @@ Template.copyCardPopup.events({ const boardId = bSelect.options[bSelect.selectedIndex].value; const textarea = $('#copy-card-title'); const title = textarea.val().trim(); - // insert new card to the bottom of new list - card.sort = Lists.findOne(card.listId).cards().count(); + + // insert new card to the top of new list + const minOrder = card.getMinSort(listId, swimlaneId); + card.sort = minOrder - 1; if (title) { card.title = title; diff --git a/models/cards.js b/models/cards.js index 73b0d48a1..ef4b2003e 100644 --- a/models/cards.js +++ b/models/cards.js @@ -691,6 +691,53 @@ Cards.helpers({ return _.contains(this.labelIds, labelId); }, + /** returns the sort number of a list + * @param listId a list id + * @param swimlaneId a swimlane id + * top sorting of the card at the top if true, or from the bottom if false + */ + getSort(listId, swimlaneId, top) { + if (!_.isBoolean(top)) { + top = true; + } + if (!listId) { + listId = this.listId; + } + if (!swimlaneId) { + swimlaneId = this.swimlaneId; + } + const selector = { + listId: listId, + swimlaneId: swimlaneId, + archived: false, + }; + const sorting = top ? 1 : -1; + const card = Cards.findOne(selector, { sort: { sort: sorting } }); + let ret = null + if (card) { + ret = card.sort; + } + return ret; + }, + + /** returns the sort number of a list from the card at the top + * @param listId a list id + * @param swimlaneId a swimlane id + */ + getMinSort(listId, swimlaneId) { + const ret = this.getSort(listId, swimlaneId, true); + return ret; + }, + + /** returns the sort number of a list from the card at the bottom + * @param listId a list id + * @param swimlaneId a swimlane id + */ + getMaxSort(listId, swimlaneId) { + const ret = this.getSort(listId, swimlaneId, false); + return ret; + }, + user() { return Users.findOne(this.userId); },