From f3f845dde85d2a82e68ee1792793c31a0a874fe3 Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Tue, 12 Sep 2017 10:36:42 +0200 Subject: Added support for sorted checklist items --- models/checklists.js | 57 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/models/checklists.js b/models/checklists.js index 2521412f..35ef8ae1 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -17,6 +17,10 @@ Checklists.attachSchema(new SimpleSchema({ 'items.$.title': { type: String, }, + 'items.$.sort': { + type: Number, + decimal: true, + }, 'items.$.isFinished': { type: Boolean, defaultValue: false, @@ -36,12 +40,34 @@ Checklists.attachSchema(new SimpleSchema({ } }, }, + sort: { + type: Number, + decimal: true, + }, + newItemIndex: { + type: Number, + decimal: true, + defaultValue: 0, + }, })); +const self = Checklists; + Checklists.helpers({ itemCount() { return this.items.length; }, + getItems() { + return this.items.sort(function (itemA, itemB) { + if (itemA.sort < itemB.sort) { + return -1; + } + if (itemA.sort > itemB.sort) { + return 1; + } + return 0; + }); + }, finishedCount() { return this.items.filter((item) => { return item.isFinished; @@ -54,7 +80,8 @@ Checklists.helpers({ return _.findWhere(this.items, { _id }); }, itemIndex(itemId) { - return _.pluck(this.items, '_id').indexOf(itemId); + const items = self.findOne({_id : this._id}).items; + return _.pluck(items, '_id').indexOf(itemId); }, }); @@ -86,14 +113,11 @@ Checklists.mutations({ //for items in checklist addItem(title) { const itemCount = this.itemCount(); - let idx = 0; - if (itemCount > 0) { - const lastId = this.items[itemCount - 1]._id; - const lastIdSuffix = lastId.substr(this._id.length); - idx = parseInt(lastIdSuffix, 10) + 1; - } - const _id = `${this._id}${idx}`; - return { $addToSet: { items: { _id, title, isFinished: false } } }; + const _id = `${this._id}${this.newItemIndex}`; + return { + $addToSet: { items: { _id, title, isFinished: false, sort: itemCount } }, + $set: { newItemIndex: this.newItemIndex + 1}, + }; }, removeItem(itemId) { return { $pull: { items: { _id: itemId } } }; @@ -143,6 +167,21 @@ Checklists.mutations({ } return {}; }, + sortItems(itemIDs) { + const validItems = []; + for (const itemID of itemIDs) { + if (this.getItem(itemID)) { + validItems.push(this.itemIndex(itemID)); + } + } + const modifiedValues = {}; + for (let i = 0; i < validItems.length; i++) { + modifiedValues[`items.${validItems[i]}.sort`] = i; + } + return { + $set: modifiedValues, + }; + }, }); if (Meteor.isServer) { -- cgit v1.2.3-1-g7c22 From f2ca520a6941da3dc60b09bfe442852511cff456 Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Tue, 12 Sep 2017 10:37:16 +0200 Subject: Prepared template for sortable checklist items --- client/components/cards/checklists.jade | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade index d04a9b60..7ecc5dd3 100644 --- a/client/components/cards/checklists.jade +++ b/client/components/cards/checklists.jade @@ -46,8 +46,8 @@ template(name="editChecklistItemForm") a.js-delete-checklist-item {{_ "delete"}}... template(name="checklistItems") - .checklist-items - each item in checklist.items + .checklist-items.js-checklist-items + each item in checklist.getItems +inlinedForm(classNames="js-edit-checklist-item" item = item checklist = checklist) +editChecklistItemForm(type = 'item' item = item checklist = checklist) else @@ -61,11 +61,10 @@ template(name="checklistItems") | {{_ 'add-checklist-item'}}... template(name='itemDetail') - .item + .item.js-checklist-item if canModifyCard .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}") .item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}} else .materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}") .item-title(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}} - -- cgit v1.2.3-1-g7c22 From 1442fd637ab74496fc43624cf8d9f6b1fe1d3c7a Mon Sep 17 00:00:00 2001 From: Jim Martens Date: Tue, 12 Sep 2017 10:38:03 +0200 Subject: Implemented checklist item sorting across checklists --- client/components/cards/checklists.js | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js index 24a78035..bd9d275a 100644 --- a/client/components/cards/checklists.js +++ b/client/components/cards/checklists.js @@ -1,14 +1,81 @@ +function initSorting(items) { + items.sortable({ + tolerance: 'pointer', + helper: 'clone', + items: '.js-checklist-item:not(.placeholder)', + axis: 'y', + distance: 7, + placeholder: 'placeholder', + scroll: false, + start(evt, ui) { + ui.placeholder.height(ui.helper.height()); + EscapeActions.executeUpTo('popup-close'); + }, + stop(evt, ui) { + const parent = ui.item.parents('.js-checklist-items'); + const orderedItems = []; + parent.find('.js-checklist-item').each(function(i, item) { + const checklistItem = Blaze.getData(item).item; + orderedItems.push(checklistItem._id); + }); + items.sortable('cancel'); + const formerParent = ui.item.parents('.js-checklist-items'); + let checklist = Blaze.getData(parent.get(0)).checklist; + const oldChecklist = Blaze.getData(formerParent.get(0)).checklist; + if (oldChecklist._id !== checklist._id) { + const currentItem = Blaze.getData(ui.item.get(0)).item; + for (let i = 0; i < orderedItems.length; i++) { + let itemId = orderedItems[i]; + if (itemId !== currentItem._id) continue; + checklist.addItem(currentItem.title); + checklist = Checklists.findOne({_id: checklist._id}); + itemId = checklist._id + (checklist.newItemIndex - 1); + if (currentItem.finished) { + checklist.finishItem(itemId); + } + orderedItems[i] = itemId; + oldChecklist.removeItem(currentItem._id); + } + } + checklist.sortItems(orderedItems); + }, + }); +} + +Template.checklists.onRendered(function () { + const self = BlazeComponent.getComponentForElement(this.firstNode); + self.itemsDom = this.$('.card-checklist-items'); + initSorting(self.itemsDom); + self.itemsDom.mousedown(function(evt) { + evt.stopPropagation(); + }); + + function userIsMember() { + return Meteor.user() && Meteor.user().isBoardMember(); + } + + // Disable sorting if the current user is not a board member + self.autorun(() => { + const $itemsDom = $(self.itemsDom); + if ($itemsDom.data('sortable')) { + $(self.itemsDom).sortable('option', 'disabled', !userIsMember()); + } + }); +}); + BlazeComponent.extendComponent({ addChecklist(event) { event.preventDefault(); const textarea = this.find('textarea.js-add-checklist-item'); const title = textarea.value.trim(); const cardId = this.currentData().cardId; + const card = Cards.findOne(cardId); if (title) { Checklists.insert({ cardId, title, + sort: card.checklists().count(), }); setTimeout(() => { this.$('.add-checklist-item').last().click(); -- cgit v1.2.3-1-g7c22 From b7c7b936409c17cb829de9ccf078bee0ac485d0a Mon Sep 17 00:00:00 2001 From: Lauri Ojansivu Date: Wed, 13 Sep 2017 20:16:22 +0300 Subject: Reorder checklists. Move checklist item to another checklist. Thanks to frmwrk123 ! Related #876 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c5c3483..c3a6f551 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# Upcoming Wekan release + +This release adds the following new features: + +* [Reorder checklists. Move checklist item to another checklist.](https://github.com/wekan/wekan/pull/1215) + +Thanks to GitHub user frmwrk123 for contributions. + # v0.37 2017-09-09 Wekan release This release adds the following new features: -- cgit v1.2.3-1-g7c22