webui: category default download location in add modal

The add-torrent save path now shows the selected category's default
location (its own save path, else the global default), greyed and
read-only. Clicking makes it editable; an overridden path then stays
put when the category changes. Resolves the "category default location
does nothing" issue by feeding the category's save path into the add.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ookami125 2026-06-23 00:33:35 -04:00
parent d55fc35c72
commit d8c4a96e88
2 changed files with 35 additions and 1 deletions

View file

@ -433,6 +433,10 @@ code.inline { background: var(--bg-3); border: 1px solid var(--line); border-rad
}
.field input[type=text]:focus, .field input[type=password]:focus, .field textarea:focus, .field select:focus,
.field input[type=file]:focus { outline: none; border-color: var(--accent); }
/* greyed default-location field: shows the category default until clicked */
.field input[type=text].path-default {
color: var(--txt-faint); background: var(--bg-2); cursor: pointer; }
.field input[type=text].path-default:hover { border-color: var(--accent); }
.field textarea { min-height: 70px; font-family: var(--mono); font-size: 12px; resize: vertical; }
/* themed file picker */

View file

@ -496,6 +496,14 @@ async function confirmDelete(hashes) {
}
/* ---------- add torrent modal ---------- */
// Default download location for a category: its own save path if set,
// otherwise the global default.
function categoryDefaultPath(catName) {
const c = state.meta.categories.find((x) => x.name === catName);
if (c && c.savePath) return c.savePath;
return state.meta.preferences.save_path || '/data/downloads';
}
function openAddModal() {
const cats = '<option value="" selected>Uncategorized</option>' +
state.meta.categories.filter((c) => c.name).map((c) => `<option value="${f.esc(c.name)}">${f.esc(c.name)}</option>`).join('');
@ -519,7 +527,9 @@ function openAddModal() {
</div>
</div></div>
<div class="field"><label>Save path</label>
<input type="text" id="addPath" value="${f.esc(state.meta.preferences.save_path || '/data/downloads')}" /></div>
<input type="text" id="addPath" class="path-default" readonly title="Click to change"
value="${f.esc(categoryDefaultPath(''))}" />
<div class="dim" id="addPathHint" style="font-size:12px;margin-top:4px">Category default click to change.</div></div>
<div class="checks">
<label><input type="checkbox" id="addPaused"> Add paused</label>
<label><input type="checkbox" id="addSeq"> Sequential download</label>
@ -606,6 +616,26 @@ function openAddModal() {
document.getElementById('addTagAdd').addEventListener('click', addTag);
input.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); addTag(); } });
})();
// save path: greyed default that tracks the category until the user edits it
(() => {
const path = document.getElementById('addPath');
const cat = document.getElementById('addCat');
const hint = document.getElementById('addPathHint');
let manual = false;
const enable = () => {
if (manual) return;
manual = true;
path.readOnly = false;
path.classList.remove('path-default');
hint.textContent = "Custom location — won't change with the category.";
path.focus();
path.select();
};
path.addEventListener('mousedown', (e) => { if (!manual) { e.preventDefault(); enable(); } });
cat.addEventListener('change', () => {
if (!manual) path.value = categoryDefaultPath(cat.value);
});
})();
// live readout of the chosen file(s)
document.getElementById('addFile').addEventListener('change', async (e) => {
const info = document.getElementById('addFileInfo');