mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
Fix migration. Replace old checklist-item sort algorithm.
This commit is contained in:
parent
bf7de463f1
commit
153960742c
7 changed files with 114 additions and 64 deletions
|
|
@ -70,7 +70,7 @@ template(name="editChecklistItemForm")
|
||||||
|
|
||||||
template(name="checklistItems")
|
template(name="checklistItems")
|
||||||
.checklist-items.js-checklist-items
|
.checklist-items.js-checklist-items
|
||||||
each item in checklist.getItemsSorted
|
each item in checklist.items
|
||||||
+inlinedForm(classNames="js-edit-checklist-item" item = item checklist = checklist)
|
+inlinedForm(classNames="js-edit-checklist-item" item = item checklist = checklist)
|
||||||
+editChecklistItemForm(type = 'item' item = item checklist = checklist)
|
+editChecklistItemForm(type = 'item' item = item checklist = checklist)
|
||||||
else
|
else
|
||||||
|
|
@ -84,7 +84,7 @@ template(name="checklistItems")
|
||||||
| {{_ 'add-checklist-item'}}...
|
| {{_ 'add-checklist-item'}}...
|
||||||
|
|
||||||
template(name='itemDetail')
|
template(name='itemDetail')
|
||||||
.item.js-checklist-item
|
.js-checklist-item.checklist-item
|
||||||
if canModifyCard
|
if canModifyCard
|
||||||
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
|
.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.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
const { calculateIndexData } = Utils;
|
||||||
|
|
||||||
function initSorting(items) {
|
function initSorting(items) {
|
||||||
items.sortable({
|
items.sortable({
|
||||||
tolerance: 'pointer',
|
tolerance: 'pointer',
|
||||||
helper: 'clone',
|
helper: 'clone',
|
||||||
items: '.js-checklist-item:not(.placeholder)',
|
items: '.js-checklist-item:not(.placeholder)',
|
||||||
axis: 'y',
|
connectWith: '.js-checklist-items',
|
||||||
|
appendTo: '.board-canvas',
|
||||||
distance: 7,
|
distance: 7,
|
||||||
placeholder: 'placeholder',
|
placeholder: 'checklist-item placeholder',
|
||||||
scroll: false,
|
scroll: false,
|
||||||
start(evt, ui) {
|
start(evt, ui) {
|
||||||
ui.placeholder.height(ui.helper.height());
|
ui.placeholder.height(ui.helper.height());
|
||||||
|
|
@ -13,33 +16,24 @@ function initSorting(items) {
|
||||||
},
|
},
|
||||||
stop(evt, ui) {
|
stop(evt, ui) {
|
||||||
const parent = ui.item.parents('.js-checklist-items');
|
const parent = ui.item.parents('.js-checklist-items');
|
||||||
const orderedItems = [];
|
const checklistId = Blaze.getData(parent.get(0)).checklist._id;
|
||||||
parent.find('.js-checklist-item').each(function(i, item) {
|
let prevItem = ui.item.prev('.js-checklist-item').get(0);
|
||||||
const checklistItem = Blaze.getData(item).item;
|
if (prevItem) {
|
||||||
orderedItems.push(checklistItem._id);
|
prevItem = Blaze.getData(prevItem).item;
|
||||||
});
|
|
||||||
items.sortable('cancel');
|
|
||||||
const formerParent = ui.item.parents('.js-checklist-items');
|
|
||||||
const 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++) {
|
|
||||||
const itemId = orderedItems[i];
|
|
||||||
if (itemId !== currentItem._id) continue;
|
|
||||||
const newItem = {
|
|
||||||
_id: checklist.getNewItemId(),
|
|
||||||
title: currentItem.title,
|
|
||||||
sort: i,
|
|
||||||
isFinished: currentItem.isFinished,
|
|
||||||
};
|
|
||||||
checklist.addFullItem(newItem);
|
|
||||||
orderedItems[i] = currentItem._id;
|
|
||||||
oldChecklist.removeItem(itemId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
checklist.sortItems(orderedItems);
|
|
||||||
}
|
}
|
||||||
|
let nextItem = ui.item.next('.js-checklist-item').get(0);
|
||||||
|
if (nextItem) {
|
||||||
|
nextItem = Blaze.getData(nextItem).item;
|
||||||
|
}
|
||||||
|
const nItems = 1;
|
||||||
|
const sortIndex = calculateIndexData(prevItem, nextItem, nItems);
|
||||||
|
const checklistDomElement = ui.item.get(0);
|
||||||
|
const checklistData = Blaze.getData(checklistDomElement);
|
||||||
|
const checklistItem = checklistData.item;
|
||||||
|
|
||||||
|
items.sortable('cancel');
|
||||||
|
|
||||||
|
checklistItem.move(checklistId, sortIndex.base);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +89,12 @@ BlazeComponent.extendComponent({
|
||||||
const checklist = this.currentData().checklist;
|
const checklist = this.currentData().checklist;
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
checklist.addItem(title);
|
ChecklistItems.insert({
|
||||||
|
title,
|
||||||
|
checklistId: checklist._id,
|
||||||
|
cardId: checklist.cardId,
|
||||||
|
sort: checklist.itemCount(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// We keep the form opened, empty it.
|
// We keep the form opened, empty it.
|
||||||
textarea.value = '';
|
textarea.value = '';
|
||||||
|
|
@ -118,7 +117,7 @@ BlazeComponent.extendComponent({
|
||||||
const checklist = this.currentData().checklist;
|
const checklist = this.currentData().checklist;
|
||||||
const item = this.currentData().item;
|
const item = this.currentData().item;
|
||||||
if (checklist && item && item._id) {
|
if (checklist && item && item._id) {
|
||||||
checklist.removeItem(item._id);
|
ChecklistItems.remove(item._id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -135,9 +134,8 @@ BlazeComponent.extendComponent({
|
||||||
|
|
||||||
const textarea = this.find('textarea.js-edit-checklist-item');
|
const textarea = this.find('textarea.js-edit-checklist-item');
|
||||||
const title = textarea.value.trim();
|
const title = textarea.value.trim();
|
||||||
const itemId = this.currentData().item._id;
|
const item = this.currentData().item;
|
||||||
const checklist = this.currentData().checklist;
|
item.setTitle(title);
|
||||||
checklist.editItem(itemId, title);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onCreated() {
|
onCreated() {
|
||||||
|
|
@ -211,7 +209,7 @@ BlazeComponent.extendComponent({
|
||||||
const checklist = this.currentData().checklist;
|
const checklist = this.currentData().checklist;
|
||||||
const item = this.currentData().item;
|
const item = this.currentData().item;
|
||||||
if (checklist && item && item._id) {
|
if (checklist && item && item._id) {
|
||||||
checklist.toggleItem(item._id);
|
item.toggleItem();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events() {
|
events() {
|
||||||
|
|
|
||||||
|
|
@ -78,34 +78,45 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||||
bottom: -600px
|
bottom: -600px
|
||||||
right: 0
|
right: 0
|
||||||
|
|
||||||
.checklist-items
|
.checklist-item
|
||||||
margin: 0 0 0.5em 1.33em
|
margin: 0 0 0.5em 1.33em
|
||||||
|
line-height: 25px
|
||||||
|
font-size: 1.1em
|
||||||
|
margin-top: 3px
|
||||||
|
display: flex
|
||||||
|
|
||||||
.item
|
&.placeholder
|
||||||
line-height: 25px
|
background: darken(white, 20%)
|
||||||
font-size: 1.1em
|
border-radius: 2px
|
||||||
margin-top: 3px
|
|
||||||
display: flex
|
|
||||||
&:hover
|
|
||||||
background-color: darken(white, 8%)
|
|
||||||
|
|
||||||
.check-box
|
&.ui-sortable-helper
|
||||||
margin-top: 5px
|
box-shadow: -2px 2px 8px rgba(0, 0, 0, .3),
|
||||||
&.is-checked
|
0 0 1px rgba(0, 0, 0, .5)
|
||||||
border-bottom: 2px solid #3cb500
|
transform: rotate(4deg)
|
||||||
border-right: 2px solid #3cb500
|
cursor: grabbing
|
||||||
|
|
||||||
.item-title
|
&:hover
|
||||||
flex: 1
|
background-color: darken(white, 8%)
|
||||||
padding-left: 10px;
|
|
||||||
&.is-checked
|
|
||||||
color: #8c8c8c
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
.js-delete-checklist-item
|
.check-box
|
||||||
@extends .delete-text
|
margin-top: 5px
|
||||||
padding: 12px 0 0 0
|
&.is-checked
|
||||||
|
border-bottom: 2px solid #3cb500
|
||||||
|
border-right: 2px solid #3cb500
|
||||||
|
|
||||||
.add-checklist-item
|
.item-title
|
||||||
padding-top: 0.5em
|
flex: 1
|
||||||
display: inline-block
|
padding-left: 10px;
|
||||||
|
&.is-checked
|
||||||
|
color: #8c8c8c
|
||||||
|
font-style: italic
|
||||||
|
|
||||||
|
.js-delete-checklist-item
|
||||||
|
margin: 0 0 0.5em 1.33em
|
||||||
|
@extends .delete-text
|
||||||
|
padding: 12px 0 0 0
|
||||||
|
|
||||||
|
.add-checklist-item
|
||||||
|
margin: 0 0 0.5em 1.33em
|
||||||
|
padding-top: 0.5em
|
||||||
|
display: inline-block
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,37 @@ Utils = {
|
||||||
return $(window).width() <= 800;
|
return $(window).width() <= 800;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
calculateIndexData(prevData, nextData, nItems = 1) {
|
||||||
|
let base, increment;
|
||||||
|
// If we drop the card to an empty column
|
||||||
|
if (!prevData && !nextData) {
|
||||||
|
base = 0;
|
||||||
|
increment = 1;
|
||||||
|
// If we drop the card in the first position
|
||||||
|
} else if (!prevData) {
|
||||||
|
base = nextData.sort - 1;
|
||||||
|
increment = -1;
|
||||||
|
// If we drop the card in the last position
|
||||||
|
} else if (!nextData) {
|
||||||
|
base = prevData.sort + 1;
|
||||||
|
increment = 1;
|
||||||
|
}
|
||||||
|
// In the general case take the average of the previous and next element
|
||||||
|
// sort indexes.
|
||||||
|
else {
|
||||||
|
const prevSortIndex = prevData.sort;
|
||||||
|
const nextSortIndex = nextData.sort;
|
||||||
|
increment = (nextSortIndex - prevSortIndex) / (nItems + 1);
|
||||||
|
base = prevSortIndex + increment;
|
||||||
|
}
|
||||||
|
// XXX Return a generator that yield values instead of a base with a
|
||||||
|
// increment number.
|
||||||
|
return {
|
||||||
|
base,
|
||||||
|
increment,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
// Determine the new sort index
|
// Determine the new sort index
|
||||||
calculateIndex(prevCardDomElement, nextCardDomElement, nCards = 1) {
|
calculateIndex(prevCardDomElement, nextCardDomElement, nCards = 1) {
|
||||||
let base, increment;
|
let base, increment;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ Activities.helpers({
|
||||||
return Checklists.findOne(this.checklistId);
|
return Checklists.findOne(this.checklistId);
|
||||||
},
|
},
|
||||||
checklistItem() {
|
checklistItem() {
|
||||||
return Checklists.findOne(this.checklistId).getItem(this.checklistItemId);
|
return ChecklistItems.findOne(this.checklistItemId);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,16 @@ ChecklistItems.mutations({
|
||||||
toggleItem() {
|
toggleItem() {
|
||||||
return { $set: { isFinished: !this.isFinished } };
|
return { $set: { isFinished: !this.isFinished } };
|
||||||
},
|
},
|
||||||
|
move(checklistId, sortIndex) {
|
||||||
|
const cardId = Checklists.findOne(checklistId).cardId;
|
||||||
|
const mutatedFields = {
|
||||||
|
cardId,
|
||||||
|
checklistId,
|
||||||
|
sort: sortIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {$set: mutatedFields};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Activities helper
|
// Activities helper
|
||||||
|
|
|
||||||
|
|
@ -191,10 +191,10 @@ Migrations.add('add-views', () => {
|
||||||
Migrations.add('add-checklist-items', () => {
|
Migrations.add('add-checklist-items', () => {
|
||||||
Checklists.find().forEach((checklist) => {
|
Checklists.find().forEach((checklist) => {
|
||||||
// Create new items
|
// Create new items
|
||||||
_.sortBy(checklist.items, 'sort').forEach((item) => {
|
_.sortBy(checklist.items, 'sort').forEach((item, index) => {
|
||||||
ChecklistItems.direct.insert({
|
ChecklistItems.direct.insert({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
sort: item.sort,
|
sort: index,
|
||||||
isFinished: item.isFinished,
|
isFinished: item.isFinished,
|
||||||
checklistId: checklist._id,
|
checklistId: checklist._id,
|
||||||
cardId: checklist.cardId,
|
cardId: checklist.cardId,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue