diff --git a/src/renderer.js b/src/renderer.js index c94ff0e..eeae4b7 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -128,6 +128,23 @@ function renderLocal() { state.localDir = entry.path; await refreshLocal(); }); + row.addEventListener('dragover', (event) => { + if (!entry.isDir) return; + event.preventDefault(); + row.classList.add('drop-target'); + }); + row.addEventListener('dragleave', () => { + row.classList.remove('drop-target'); + }); + row.addEventListener('drop', async (event) => { + if (!entry.isDir) return; + event.preventDefault(); + row.classList.remove('drop-target'); + const payloadRaw = event.dataTransfer.getData('application/oddl'); + if (!payloadRaw) return; + const payload = JSON.parse(payloadRaw); + await triggerDownload(payload, entry.path); + }); el.localListBody.appendChild(row); }); } @@ -160,6 +177,15 @@ function renderRemote() { row.dataset.href = entry.href; row.dataset.isDir = entry.isDir ? '1' : '0'; }); + row.setAttribute('draggable', 'true'); + row.addEventListener('dragstart', (event) => { + const payload = { + url: entry.href, + isDir: entry.isDir, + }; + event.dataTransfer.setData('application/oddl', JSON.stringify(payload)); + event.dataTransfer.effectAllowed = 'copy'; + }); el.remoteListBody.appendChild(row); }); } @@ -324,6 +350,23 @@ async function refreshRemote() { renderRemoteTree(); } +async function triggerDownload(payload, destinationDir) { + if (!destinationDir) { + log('Choose a local destination first.'); + return; + } + if (!payload?.url) return; + log(`Queueing ${payload.url}`); + await window.oddl.downloadItem({ + url: payload.url, + destDir: destinationDir, + isDir: Boolean(payload.isDir), + useWget: el.useWget.checked, + }); + log('Done.'); + await refreshLocal(); +} + function setupResizer(listEl, resizerEl) { let startX = 0; let startWidth = 0; @@ -416,21 +459,29 @@ el.downloadBtn.addEventListener('click', async () => { log('Select a remote file or folder first.'); return; } - if (!state.localDir) { - log('Choose a local destination first.'); - return; - } - const href = selected.dataset.href; - const isDir = selected.dataset.isDir === '1'; - log(`Queueing ${href}`); - await window.oddl.downloadItem({ - url: href, - destDir: state.localDir, - isDir, - useWget: el.useWget.checked, - }); - log('Done.'); - await refreshLocal(); + const payload = { + url: selected.dataset.href, + isDir: selected.dataset.isDir === '1', + }; + await triggerDownload(payload, state.localDir); +}); + +el.localListBody.addEventListener('dragover', (event) => { + event.preventDefault(); + el.localListBody.closest('.panel-body')?.classList.add('drop-target'); +}); + +el.localListBody.addEventListener('dragleave', () => { + el.localListBody.closest('.panel-body')?.classList.remove('drop-target'); +}); + +el.localListBody.addEventListener('drop', async (event) => { + event.preventDefault(); + el.localListBody.closest('.panel-body')?.classList.remove('drop-target'); + const payloadRaw = event.dataTransfer.getData('application/oddl'); + if (!payloadRaw) return; + const payload = JSON.parse(payloadRaw); + await triggerDownload(payload, state.localDir); }); window.oddl.onLog((message) => log(message)); diff --git a/src/styles.css b/src/styles.css index bcfbe91..7e30b21 100644 --- a/src/styles.css +++ b/src/styles.css @@ -277,6 +277,16 @@ body { background: var(--selected); } +.row.drop-target { + outline: 2px dashed var(--progress-fill-start); + outline-offset: -2px; +} + +.panel-body.drop-target { + outline: 2px dashed var(--progress-fill-start); + outline-offset: -6px; +} + .log { margin: 0 24px 24px; border: 1px solid var(--border);