mirror of
https://github.com/wekan/wekan.git
synced 2025-12-18 16:30:13 +01:00
Fix add and drag drop attachments to minicards and card.
Thanks to xet7 ! Fixes #5946, fixes #5436, fixes #2936, fixes #1926, fixes #300, fixes #142
This commit is contained in:
parent
cea414b589
commit
b06daff4c7
6 changed files with 122 additions and 75 deletions
|
|
@ -496,3 +496,10 @@
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Global file drag over state for board canvas */
|
||||||
|
.board-canvas.file-drag-over {
|
||||||
|
background-color: rgba(0, 123, 255, 0.05) !important;
|
||||||
|
border: 2px dashed #007bff !important;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -721,6 +721,31 @@ BlazeComponent.extendComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'click .js-empty-board-add-swimlane': Popup.open('swimlaneAdd'),
|
'click .js-empty-board-add-swimlane': Popup.open('swimlaneAdd'),
|
||||||
|
// Global drag and drop file upload handlers for better visual feedback
|
||||||
|
'dragover .board-canvas'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
|
event.preventDefault();
|
||||||
|
// Add visual indicator that files can be dropped
|
||||||
|
$('.board-canvas').addClass('file-drag-over');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'dragleave .board-canvas'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
|
// Only remove class if we're leaving the board canvas entirely
|
||||||
|
if (!event.currentTarget.contains(event.relatedTarget)) {
|
||||||
|
$('.board-canvas').removeClass('file-drag-over');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'drop .board-canvas'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
|
event.preventDefault();
|
||||||
|
$('.board-canvas').removeClass('file-drag-over');
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,7 @@ export function handleFileUpload(card, files) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user can modify the card
|
// Check if user can modify the card
|
||||||
if (!card.canModifyCard()) {
|
if (!Utils.canModifyCard()) {
|
||||||
if (process.env.DEBUG === 'true') {
|
if (process.env.DEBUG === 'true') {
|
||||||
console.warn('User does not have permission to modify this card');
|
console.warn('User does not have permission to modify this card');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -504,29 +504,37 @@ BlazeComponent.extendComponent({
|
||||||
},
|
},
|
||||||
// Drag and drop file upload handlers
|
// Drag and drop file upload handlers
|
||||||
'dragover .js-card-details'(event) {
|
'dragover .js-card-details'(event) {
|
||||||
|
// Only prevent default for file drags to avoid interfering with other drag operations
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'dragenter .js-card-details'(event) {
|
'dragenter .js-card-details'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const card = this.data();
|
const card = this.data();
|
||||||
const board = card.board();
|
const board = card.board();
|
||||||
// Only allow drag-and-drop if user can modify card and board allows attachments
|
// Only allow drag-and-drop if user can modify card and board allows attachments
|
||||||
if (card.canModifyCard() && board && board.allowsAttachments) {
|
if (Utils.canModifyCard() && board && board.allowsAttachments) {
|
||||||
// Check if the drag contains files
|
|
||||||
const dataTransfer = event.originalEvent.dataTransfer;
|
|
||||||
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
|
||||||
$(event.currentTarget).addClass('is-dragging-over');
|
$(event.currentTarget).addClass('is-dragging-over');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'dragleave .js-card-details'(event) {
|
'dragleave .js-card-details'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
$(event.currentTarget).removeClass('is-dragging-over');
|
$(event.currentTarget).removeClass('is-dragging-over');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'drop .js-card-details'(event) {
|
'drop .js-card-details'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
$(event.currentTarget).removeClass('is-dragging-over');
|
$(event.currentTarget).removeClass('is-dragging-over');
|
||||||
|
|
@ -535,18 +543,12 @@ BlazeComponent.extendComponent({
|
||||||
const board = card.board();
|
const board = card.board();
|
||||||
|
|
||||||
// Check permissions
|
// Check permissions
|
||||||
if (!card.canModifyCard() || !board || !board.allowsAttachments) {
|
if (!Utils.canModifyCard() || !board || !board.allowsAttachments) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a file drop (not a checklist item reorder)
|
// Check if this is a file drop (not a checklist item reorder)
|
||||||
const dataTransfer = event.originalEvent.dataTransfer;
|
if (!dataTransfer.files || dataTransfer.files.length === 0) {
|
||||||
if (!dataTransfer || !dataTransfer.files || dataTransfer.files.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the drop contains files (not just text/HTML)
|
|
||||||
if (!dataTransfer.types.includes('Files')) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,6 +556,7 @@ BlazeComponent.extendComponent({
|
||||||
if (files && files.length > 0) {
|
if (files && files.length > 0) {
|
||||||
handleFileUpload(card, files);
|
handleFileUpload(card, files);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -111,29 +111,37 @@ BlazeComponent.extendComponent({
|
||||||
'click .js-open-minicard-details-menu': Popup.open('minicardDetailsActions'),
|
'click .js-open-minicard-details-menu': Popup.open('minicardDetailsActions'),
|
||||||
// Drag and drop file upload handlers
|
// Drag and drop file upload handlers
|
||||||
'dragover .minicard'(event) {
|
'dragover .minicard'(event) {
|
||||||
|
// Only prevent default for file drags to avoid interfering with sortable
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'dragenter .minicard'(event) {
|
'dragenter .minicard'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const card = this.data();
|
const card = this.data();
|
||||||
const board = card.board();
|
const board = card.board();
|
||||||
// Only allow drag-and-drop if user can modify card and board allows attachments
|
// Only allow drag-and-drop if user can modify card and board allows attachments
|
||||||
if (card.canModifyCard() && board && board.allowsAttachments) {
|
if (Utils.canModifyCard() && board && board.allowsAttachments) {
|
||||||
// Check if the drag contains files
|
|
||||||
const dataTransfer = event.originalEvent.dataTransfer;
|
|
||||||
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
|
||||||
$(event.currentTarget).addClass('is-dragging-over');
|
$(event.currentTarget).addClass('is-dragging-over');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'dragleave .minicard'(event) {
|
'dragleave .minicard'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
$(event.currentTarget).removeClass('is-dragging-over');
|
$(event.currentTarget).removeClass('is-dragging-over');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'drop .minicard'(event) {
|
'drop .minicard'(event) {
|
||||||
|
const dataTransfer = event.originalEvent.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
$(event.currentTarget).removeClass('is-dragging-over');
|
$(event.currentTarget).removeClass('is-dragging-over');
|
||||||
|
|
@ -142,18 +150,12 @@ BlazeComponent.extendComponent({
|
||||||
const board = card.board();
|
const board = card.board();
|
||||||
|
|
||||||
// Check permissions
|
// Check permissions
|
||||||
if (!card.canModifyCard() || !board || !board.allowsAttachments) {
|
if (!Utils.canModifyCard() || !board || !board.allowsAttachments) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a file drop (not a card reorder)
|
// Check if this is a file drop (not a card reorder)
|
||||||
const dataTransfer = event.originalEvent.dataTransfer;
|
if (!dataTransfer.files || dataTransfer.files.length === 0) {
|
||||||
if (!dataTransfer || !dataTransfer.files || dataTransfer.files.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the drop contains files (not just text/HTML)
|
|
||||||
if (!dataTransfer.types.includes('Files')) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +163,7 @@ BlazeComponent.extendComponent({
|
||||||
if (files && files.length > 0) {
|
if (files && files.length > 0) {
|
||||||
handleFileUpload(card, files);
|
handleFileUpload(card, files);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,15 @@ BlazeComponent.extendComponent({
|
||||||
} else {
|
} else {
|
||||||
$cards.sortable({
|
$cards.sortable({
|
||||||
handle: '.minicard',
|
handle: '.minicard',
|
||||||
|
// Prevent sortable from interfering with file drag and drop
|
||||||
|
start: function(event, ui) {
|
||||||
|
// Check if this is a file drag operation
|
||||||
|
const dataTransfer = event.originalEvent?.dataTransfer;
|
||||||
|
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||||
|
// Cancel sortable for file drags
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue