plugins(files): Feature 7 — Drag-and-Drop
- Items are draggable (draggable='true') - Multi-file drag from selection (selectedPaths) - Drop on folder moves files via api.files.move() - Visual feedback: .files-dragging (opacity) + .files-drag-over (dashed outline) - No-op when source === target folder
This commit is contained in:
parent
e74499a329
commit
e5c63576d0
|
|
@ -63,7 +63,9 @@
|
|||
'.files-modal-btn.confirm{background:#4ecca3;color:#111;border-color:#4ecca3}',
|
||||
'.files-modal-btn.confirm:hover{background:#3dbb92}',
|
||||
'.files-modal-btn.danger{background:#e74c3c;color:#fff;border-color:#e74c3c}',
|
||||
'.files-modal-btn.danger:hover{background:#c0392b}'
|
||||
'.files-modal-btn.danger:hover{background:#c0392b}',
|
||||
'.files-dragging{opacity:.5}',
|
||||
'.files-drag-over{outline:2px dashed #4ecca3;outline-offset:-2px;background:rgba(78,204,163,.08)}'
|
||||
].join('\n');
|
||||
|
||||
function el(tag, attrs, children) {
|
||||
|
|
@ -375,9 +377,26 @@
|
|||
'data-file-name': entry.name,
|
||||
'data-file-type': entry.type,
|
||||
'data-file-path': entry.relativePath,
|
||||
draggable: 'true',
|
||||
tabindex: '0',
|
||||
onClick: function (e) { selectEntry(entry, e); },
|
||||
onDblclick: function () { openEntry(entry); }
|
||||
onDblclick: function () { openEntry(entry); },
|
||||
onDragstart: function (e) {
|
||||
var paths = [];
|
||||
if (selectedPaths[entry.relativePath] && selectedCount() > 1) {
|
||||
paths = Object.keys(selectedPaths);
|
||||
} else {
|
||||
selectedPaths = {};
|
||||
selectedPaths[entry.relativePath] = true;
|
||||
lastClickedPath = entry.relativePath;
|
||||
renderList();
|
||||
paths = [entry.relativePath];
|
||||
}
|
||||
e.dataTransfer.setData('application/files-paths', JSON.stringify(paths));
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
row.classList.add('files-dragging');
|
||||
},
|
||||
onDragend: function () { row.classList.remove('files-dragging'); }
|
||||
}, [
|
||||
el('div', { className: 'files-namecell' }, [
|
||||
el('span', { className: 'files-item-icon', innerHTML: fileIcon(entry) }),
|
||||
|
|
@ -738,6 +757,50 @@
|
|||
}
|
||||
});
|
||||
|
||||
function moveFiles(sourcePaths, targetDirPath) {
|
||||
var promises = sourcePaths.filter(function (p) { return parentPath(p) !== targetDirPath; }).map(function (p) {
|
||||
var name = baseName(p);
|
||||
var to = targetDirPath ? targetDirPath + '/' + name : name;
|
||||
return api.files.move(p, to, { overwrite: false });
|
||||
});
|
||||
if (promises.length === 0) return Promise.resolve();
|
||||
return Promise.allSettled(promises).then(function () { loadEntries(); });
|
||||
}
|
||||
|
||||
listContainer.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
var row = e.target.closest('.files-item');
|
||||
if (row) {
|
||||
row.classList.add('files-drag-over');
|
||||
} else {
|
||||
listContainer.classList.add('files-drag-over');
|
||||
}
|
||||
});
|
||||
|
||||
listContainer.addEventListener('dragleave', function (e) {
|
||||
var row = e.target.closest('.files-item');
|
||||
if (row) row.classList.remove('files-drag-over');
|
||||
if (!row) listContainer.classList.remove('files-drag-over');
|
||||
});
|
||||
|
||||
listContainer.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
listContainer.classList.remove('files-drag-over');
|
||||
var rows = listContainer.querySelectorAll('.files-drag-over');
|
||||
for (var i = 0; i < rows.length; i++) rows[i].classList.remove('files-drag-over');
|
||||
var raw = e.dataTransfer.getData('application/files-paths');
|
||||
if (!raw) return;
|
||||
var sourcePaths;
|
||||
try { sourcePaths = JSON.parse(raw); } catch (err) { return; }
|
||||
if (!sourcePaths || !sourcePaths.length) return;
|
||||
var row = e.target.closest('.files-item');
|
||||
if (row && row.getAttribute('data-file-type') === 'folder') {
|
||||
var targetRel = row.getAttribute('data-file-path');
|
||||
moveFiles(sourcePaths, targetRel);
|
||||
}
|
||||
});
|
||||
|
||||
containerEl.addEventListener('keydown', function (event) {
|
||||
if (event.target && ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].indexOf(event.target.tagName) !== -1) return;
|
||||
if (event.key === 'Enter') openEntry(selectedEntry());
|
||||
|
|
|
|||
Loading…
Reference in New Issue