Merge pull request #238 from EdouardVanbelle/feat/drag-n-drop-in-breadcrumb
feat: drag 'n drop into the breadcrumb
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
.breadcrumb-item {
|
.breadcrumb-item {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
border: 2px solid transparent;
|
||||||
transition: background 0.15s, color 0.15s;
|
transition: background 0.15s, color 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +21,11 @@
|
|||||||
color: #5a6f8a;
|
color: #5a6f8a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.breadcrumb-link.drop-target {
|
||||||
|
background-color: rgba(255, 193, 7, 0.1);
|
||||||
|
border: 2px dashed #ffc107;
|
||||||
|
}
|
||||||
|
|
||||||
.breadcrumb-link:hover {
|
.breadcrumb-link:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: #ff5e3a;
|
color: #ff5e3a;
|
||||||
|
|||||||
+67
-35
@@ -516,34 +516,15 @@ const ui = {
|
|||||||
}
|
}
|
||||||
breadcrumb.appendChild(homeIcon);
|
breadcrumb.appendChild(homeIcon);
|
||||||
|
|
||||||
// -- Root/Home folder name (if available) --
|
// -- Root/Home folder name (if available) is always the first element of the breadcrumb --
|
||||||
|
// TODO clarify the difference between homeIcon & this first element
|
||||||
if (window.app.userHomeFolderName) {
|
if (window.app.userHomeFolderName) {
|
||||||
const separator1 = document.createElement('span');
|
if (path.length === 0 || path[0].id !== window.app.userHomeFolderId) {
|
||||||
separator1.className = 'breadcrumb-separator';
|
path.unshift({ name: window.app.userHomeFolderName, id: window.app.userHomeFolderId});
|
||||||
separator1.textContent = '>';
|
|
||||||
breadcrumb.appendChild(separator1);
|
|
||||||
|
|
||||||
const rootFolderItem = document.createElement('span');
|
|
||||||
rootFolderItem.className = 'breadcrumb-item';
|
|
||||||
rootFolderItem.textContent = window.app.userHomeFolderName;
|
|
||||||
|
|
||||||
// If we're at the home folder level (no deeper navigation), show as current
|
|
||||||
if (path.length === 0) {
|
|
||||||
rootFolderItem.classList.add('breadcrumb-current');
|
|
||||||
} else {
|
|
||||||
// Otherwise clickable to go back to home
|
|
||||||
rootFolderItem.classList.add('breadcrumb-link');
|
|
||||||
rootFolderItem.addEventListener('click', () => {
|
|
||||||
window.app.breadcrumbPath = [];
|
|
||||||
window.app.currentPath = window.app.userHomeFolderId;
|
|
||||||
self.updateBreadcrumb();
|
|
||||||
window.loadFiles();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
breadcrumb.appendChild(rootFolderItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Intermediate + current segments --
|
// -- Root/Home + Intermediate + current segments --
|
||||||
path.forEach((segment, index) => {
|
path.forEach((segment, index) => {
|
||||||
const isLast = index === path.length - 1;
|
const isLast = index === path.length - 1;
|
||||||
|
|
||||||
@@ -557,6 +538,7 @@ const ui = {
|
|||||||
const item = document.createElement('span');
|
const item = document.createElement('span');
|
||||||
item.className = 'breadcrumb-item';
|
item.className = 'breadcrumb-item';
|
||||||
item.textContent = segment.name;
|
item.textContent = segment.name;
|
||||||
|
item.dataset.folderId = segment.id;
|
||||||
|
|
||||||
if (!isLast) {
|
if (!isLast) {
|
||||||
// Intermediate segment: clickable – truncate path to this level
|
// Intermediate segment: clickable – truncate path to this level
|
||||||
@@ -567,6 +549,40 @@ const ui = {
|
|||||||
self.updateBreadcrumb();
|
self.updateBreadcrumb();
|
||||||
window.loadFiles();
|
window.loadFiles();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// can drag files on this folder
|
||||||
|
// dragover – only folders are valid drop targets
|
||||||
|
item.addEventListener('dragover', (e) => {
|
||||||
|
const card = e.target.closest("span");
|
||||||
|
if (!card || !card.dataset.folderId) return;
|
||||||
|
e.preventDefault();
|
||||||
|
card.classList.add('drop-target');
|
||||||
|
});
|
||||||
|
|
||||||
|
// dragleave
|
||||||
|
item.addEventListener('dragleave', (e) => {
|
||||||
|
console.log( "dragleave ",e );
|
||||||
|
const card = e.target.closest("span");
|
||||||
|
if (!card || !card.dataset.folderId) return;
|
||||||
|
card.classList.remove('drop-target');
|
||||||
|
});
|
||||||
|
|
||||||
|
// drop – only folders accept drops
|
||||||
|
item.addEventListener('drop', async (e) => {
|
||||||
|
const card = e.target.closest("span");
|
||||||
|
if (!card) return;
|
||||||
|
const targetFolderId = card.dataset.folderId;
|
||||||
|
if (!targetFolderId) return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
card.classList.remove('drop-target');
|
||||||
|
|
||||||
|
const id = e.dataTransfer.getData('text/plain');
|
||||||
|
const isFolder =
|
||||||
|
e.dataTransfer.getData('application/oxicloud-folder') === 'true';
|
||||||
|
|
||||||
|
await self.move( id, isFolder, targetFolderId);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Last segment: current location, not clickable
|
// Last segment: current location, not clickable
|
||||||
item.classList.add('breadcrumb-current');
|
item.classList.add('breadcrumb-current');
|
||||||
@@ -575,6 +591,32 @@ const ui = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: support multiple elements to move ? (API does)
|
||||||
|
/**
|
||||||
|
* proceed to the drag & drop
|
||||||
|
* @param {string} sourceId to move (can be a uniq object or)
|
||||||
|
* @param {boolean} sourceIsAFolder
|
||||||
|
* @param {string} targetFolderId
|
||||||
|
*/
|
||||||
|
async move(sourceId, sourceIsAFolder, targetFolderId) {
|
||||||
|
if (!sourceId) return;
|
||||||
|
|
||||||
|
console.log(`request move ${ sourceIsAFolder ? "folder": "file"} ${sourceId} to folder ${targetFolderId}`);
|
||||||
|
|
||||||
|
if (sourceIsAFolder) {
|
||||||
|
if (sourceId === targetFolderId) {
|
||||||
|
alert("You cannot move a folder to itself");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: handle errors...
|
||||||
|
await fileOps.moveFolder(sourceId, targetFolderId);
|
||||||
|
} else {
|
||||||
|
// TODO: handle errors...
|
||||||
|
await fileOps.moveFile(sourceId, targetFolderId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a file can be previewed in the viewer
|
* Check if a file can be previewed in the viewer
|
||||||
* @param {Object} file - File object with mime_type property
|
* @param {Object} file - File object with mime_type property
|
||||||
@@ -951,17 +993,7 @@ const ui = {
|
|||||||
const isFolder =
|
const isFolder =
|
||||||
e.dataTransfer.getData('application/oxicloud-folder') === 'true';
|
e.dataTransfer.getData('application/oxicloud-folder') === 'true';
|
||||||
|
|
||||||
if (id) {
|
await self.move( id, isFolder, targetFolderId);
|
||||||
if (isFolder) {
|
|
||||||
if (id === targetFolderId) {
|
|
||||||
alert("You cannot move a folder to itself");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await fileOps.moveFolder(id, targetFolderId);
|
|
||||||
} else {
|
|
||||||
await fileOps.moveFile(id, targetFolderId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user