mirror of
https://github.com/wekan/wekan.git
synced 2026-02-09 01:34:21 +01:00
Fix move and copy popup duplicate view.
Thanks to mimZD and xet7 ! Fixes #6102
This commit is contained in:
parent
5836e50e69
commit
631c250f40
3 changed files with 165 additions and 61 deletions
|
|
@ -847,27 +847,111 @@ template(name="exportCardPopup")
|
|||
| {{_ 'export-card-pdf'}}
|
||||
|
||||
template(name="moveCardPopup")
|
||||
+copyAndMoveCard
|
||||
unless currentUser.isWorker
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionBoardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
each swimlanes
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionSwimlaneId _id}}selected{{/if}}") {{add @index 1}}. {{isTitleDefault title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each lists
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionListId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'cards'}}:
|
||||
select.js-select-cards
|
||||
each cards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionCardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
div
|
||||
input(type="radio" name="position" value="above" checked id="position-above" style="display: inline")
|
||||
label(for="position-above") {{_ 'above-selected-card'}}
|
||||
div
|
||||
input(type="radio" name="position" value="below" id="position-below" style="display: inline")
|
||||
label(for="position-below") {{_ 'below-selected-card'}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-done {{_ 'done'}}
|
||||
|
||||
template(name="copyCardPopup")
|
||||
label(for='copy-card-title') {{_ 'title'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= getTitle
|
||||
+copyAndMoveCard
|
||||
unless currentUser.isWorker
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionBoardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
each swimlanes
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionSwimlaneId _id}}selected{{/if}}") {{add @index 1}}. {{isTitleDefault title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each lists
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionListId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'cards'}}:
|
||||
select.js-select-cards
|
||||
each cards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionCardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
div
|
||||
input(type="radio" name="position" value="above" checked id="position-above" style="display: inline")
|
||||
label(for="position-above") {{_ 'above-selected-card'}}
|
||||
div
|
||||
input(type="radio" name="position" value="below" id="position-below" style="display: inline")
|
||||
label(for="position-below") {{_ 'below-selected-card'}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-done {{_ 'done'}}
|
||||
|
||||
template(name="copyManyCardsPopup")
|
||||
label(for='copy-checklist-cards-title') {{_ 'copyManyCardsPopup-instructions'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
| {{_ 'copyManyCardsPopup-format'}}
|
||||
+copyAndMoveCard
|
||||
unless currentUser.isWorker
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionBoardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
each swimlanes
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionSwimlaneId _id}}selected{{/if}}") {{add @index 1}}. {{isTitleDefault title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each lists
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionListId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
label {{_ 'cards'}}:
|
||||
select.js-select-cards
|
||||
each cards
|
||||
option(value="{{_id}}" selected="{{#if isDialogOptionCardId _id}}selected{{/if}}") {{add @index 1}}. {{title}}
|
||||
|
||||
div
|
||||
input(type="radio" name="position" value="above" checked id="position-above" style="display: inline")
|
||||
label(for="position-above") {{_ 'above-selected-card'}}
|
||||
div
|
||||
input(type="radio" name="position" value="below" id="position-below" style="display: inline")
|
||||
label(for="position-below") {{_ 'below-selected-card'}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-done {{_ 'done'}}
|
||||
|
||||
template(name="convertChecklistItemToCardPopup")
|
||||
label(for='convert-checklist-item-to-card-title') {{_ 'title'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= item.title
|
||||
+copyAndMoveCard
|
||||
|
||||
template(name="copyAndMoveCard")
|
||||
unless currentUser.isWorker
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,11 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
'click span.badge-icon.fa.fa-sort, click span.badge-text.check-list-sort' : Popup.open("editCardSortOrder"),
|
||||
'click .minicard-labels' : this.cardLabelsPopup,
|
||||
'click .js-open-minicard-details-menu': Popup.open('cardDetailsActions'),
|
||||
'click .js-open-minicard-details-menu'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
Popup.open('cardDetailsActions').call(this, event);
|
||||
},
|
||||
// Drag and drop file upload handlers
|
||||
'dragover .minicard'(event) {
|
||||
// Only prevent default for file drags to avoid interfering with sortable
|
||||
|
|
@ -306,35 +310,3 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
}).register('editCardSortOrderPopup');
|
||||
|
||||
Template.cardDetailsActionsPopup.events({
|
||||
'click .js-due-date': Popup.open('editCardDueDate'),
|
||||
'click .js-move-card': Popup.open('moveCard'),
|
||||
'click .js-copy-card': Popup.open('copyCard'),
|
||||
'click .js-set-card-color': Popup.open('setCardColor'),
|
||||
'click .js-add-labels': Popup.open('cardLabels'),
|
||||
'click .js-link': Popup.open('linkCard'),
|
||||
'click .js-move-card-to-top'(event) {
|
||||
event.preventDefault();
|
||||
const minOrder = this.getMinSort();
|
||||
this.move(this.boardId, this.swimlaneId, this.listId, minOrder - 1);
|
||||
Popup.back();
|
||||
},
|
||||
async 'click .js-move-card-to-bottom'(event) {
|
||||
event.preventDefault();
|
||||
const maxOrder = this.getMaxSort();
|
||||
await this.move(this.boardId, this.swimlaneId, this.listId, maxOrder + 1);
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-archive': Popup.afterConfirm('cardArchive', async function () {
|
||||
Popup.close();
|
||||
await this.archive();
|
||||
Utils.goBoardId(this.boardId);
|
||||
}),
|
||||
'click .js-toggle-watch-card'() {
|
||||
const currentCard = this;
|
||||
const level = currentCard.findWatcher(Meteor.userId()) ? null : 'watching';
|
||||
Meteor.call('watch', 'card', currentCard._id, level, (err, ret) => {
|
||||
if (!err && ret) Popup.back();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
|
||||
const subManager = new SubsManager();
|
||||
|
||||
|
|
@ -288,6 +289,25 @@ Template.moveSelectionPopup.helpers({
|
|||
isDialogOptionListId(listId) {
|
||||
return Template.instance().selectedListId.get() === listId;
|
||||
},
|
||||
isTitleDefault(title) {
|
||||
if (
|
||||
title.startsWith("key 'default") &&
|
||||
title.endsWith('returned an object instead of string.')
|
||||
) {
|
||||
const translated = `${TAPi18n.__('defaultdefault')}`;
|
||||
if (
|
||||
translated.startsWith("key 'default") &&
|
||||
translated.endsWith('returned an object instead of string.')
|
||||
) {
|
||||
return 'Default';
|
||||
}
|
||||
return translated;
|
||||
}
|
||||
if (title === 'Default') {
|
||||
return `${TAPi18n.__('defaultdefault')}`;
|
||||
}
|
||||
return title;
|
||||
},
|
||||
});
|
||||
|
||||
Template.moveSelectionPopup.events({
|
||||
|
|
@ -329,7 +349,7 @@ Template.moveSelectionPopup.events({
|
|||
} else {
|
||||
// If no card selected, move to end
|
||||
const board = ReactiveCache.getBoard(boardId);
|
||||
const cards = board.cards({ swimlaneId, listId }).sort('sort');
|
||||
const cards = board.cards({ swimlaneId, listId }).sort((a, b) => a.sort - b.sort);
|
||||
if (cards.length > 0) {
|
||||
sortIndex = cards[cards.length - 1].sort + 1;
|
||||
}
|
||||
|
|
@ -419,6 +439,25 @@ Template.copySelectionPopup.helpers({
|
|||
isDialogOptionListId(listId) {
|
||||
return Template.instance().selectedListId.get() === listId;
|
||||
},
|
||||
isTitleDefault(title) {
|
||||
if (
|
||||
title.startsWith("key 'default") &&
|
||||
title.endsWith('returned an object instead of string.')
|
||||
) {
|
||||
const translated = `${TAPi18n.__('defaultdefault')}`;
|
||||
if (
|
||||
translated.startsWith("key 'default") &&
|
||||
translated.endsWith('returned an object instead of string.')
|
||||
) {
|
||||
return 'Default';
|
||||
}
|
||||
return translated;
|
||||
}
|
||||
if (title === 'Default') {
|
||||
return `${TAPi18n.__('defaultdefault')}`;
|
||||
}
|
||||
return title;
|
||||
},
|
||||
});
|
||||
|
||||
Template.copySelectionPopup.events({
|
||||
|
|
@ -447,31 +486,40 @@ Template.copySelectionPopup.events({
|
|||
const position = instance.position.get();
|
||||
|
||||
mutateSelectedCards(async (card) => {
|
||||
const newCardId = await card.copy(boardId, swimlaneId, listId);
|
||||
if (newCardId) {
|
||||
const newCard = ReactiveCache.getCard(newCardId);
|
||||
if (newCard) {
|
||||
let sortIndex = 0;
|
||||
if (cardId) {
|
||||
const targetCard = ReactiveCache.getCard(cardId);
|
||||
if (targetCard) {
|
||||
if (position === 'above') {
|
||||
sortIndex = targetCard.sort - 0.5;
|
||||
} else {
|
||||
sortIndex = targetCard.sort + 0.5;
|
||||
}
|
||||
}
|
||||
const newCardId = await Meteor.callAsync(
|
||||
'copyCard',
|
||||
card._id,
|
||||
boardId,
|
||||
swimlaneId,
|
||||
listId,
|
||||
true,
|
||||
{ title: card.title },
|
||||
);
|
||||
if (!newCardId) return;
|
||||
|
||||
const newCard = ReactiveCache.getCard(newCardId);
|
||||
if (!newCard) return;
|
||||
|
||||
let sortIndex = 0;
|
||||
if (cardId) {
|
||||
const targetCard = ReactiveCache.getCard(cardId);
|
||||
if (targetCard) {
|
||||
if (position === 'above') {
|
||||
sortIndex = targetCard.sort - 0.5;
|
||||
} else {
|
||||
// To end
|
||||
const board = ReactiveCache.getBoard(boardId);
|
||||
const cards = board.cards({ swimlaneId, listId }).sort('sort');
|
||||
if (cards.length > 0) {
|
||||
sortIndex = cards[cards.length - 1].sort + 1;
|
||||
}
|
||||
sortIndex = targetCard.sort + 0.5;
|
||||
}
|
||||
newCard.setSort(sortIndex);
|
||||
}
|
||||
} else {
|
||||
// To end
|
||||
const board = ReactiveCache.getBoard(boardId);
|
||||
const cards = board.cards({ swimlaneId, listId }).sort((a, b) => a.sort - b.sort);
|
||||
if (cards.length > 0) {
|
||||
sortIndex = cards[cards.length - 1].sort + 1;
|
||||
}
|
||||
}
|
||||
|
||||
await newCard.move(boardId, swimlaneId, listId, sortIndex);
|
||||
});
|
||||
EscapeActions.executeUpTo('multiselection');
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue