diff --git a/static/app.js b/static/app.js
index 154b23c..e28c374 100644
--- a/static/app.js
+++ b/static/app.js
@@ -265,7 +265,13 @@ $("#scan-btn").addEventListener("click", async () => {
api("/api/requests?status=missing"),
]);
scanItems = scan.items;
+ // selection state lives here, not in the DOM, so it survives paging
+ scanItems.forEach((item) => {
+ item.request_id = item.suggested_request_id;
+ item.checked = !!item.suggested_request_id;
+ });
missingReqs = reqs;
+ importPage = 0;
$("#scan-info").textContent = `${scan.items.length} Kandidat(en) in ${scan.download_dir}`;
renderImportTable();
} catch (err) {
@@ -274,22 +280,36 @@ $("#scan-btn").addEventListener("click", async () => {
}
});
+let importPage = 0;
+const IMPORT_PAGE_SIZE = 25;
+
function renderImportTable() {
const table = $("#import-table");
const tbody = table.querySelector("tbody");
- if (!scanItems.length) { table.hidden = true; $("#import-btn").hidden = true; return; }
- tbody.innerHTML = scanItems
- .map((item, i) => {
+ if (!scanItems.length) {
+ table.hidden = true;
+ $("#import-btn").hidden = true;
+ $("#import-pager").hidden = true;
+ return;
+ }
+ const pages = Math.ceil(scanItems.length / IMPORT_PAGE_SIZE);
+ importPage = Math.min(importPage, pages - 1);
+ const start = importPage * IMPORT_PAGE_SIZE;
+ const pageItems = scanItems.slice(start, start + IMPORT_PAGE_SIZE);
+
+ tbody.innerHTML = pageItems
+ .map((item, k) => {
+ const i = start + k;
const opts = missingReqs
.filter((r) => r.media_type === item.media_type)
.map(
(r) =>
- ``
)
.join("");
return `
- |
+ |
${esc(item.name)}${item.is_dir ? " 📁" : ""} |
${esc(item.media_type)} |
@@ -302,11 +322,34 @@ function renderImportTable() {
.join("");
table.hidden = false;
$("#import-btn").hidden = false;
+
tbody.querySelectorAll("[data-quick]").forEach((b) =>
b.addEventListener("click", () => openQuickDialog(parseInt(b.dataset.quick)))
);
+ tbody.querySelectorAll("[data-check]").forEach((c) =>
+ c.addEventListener("change", () => (scanItems[c.dataset.check].checked = c.checked))
+ );
+ tbody.querySelectorAll("[data-select]").forEach((s) =>
+ s.addEventListener("change", () => {
+ const item = scanItems[s.dataset.select];
+ item.request_id = s.value ? parseInt(s.value) : null;
+ item.checked = !!item.request_id;
+ const check = tbody.querySelector(`[data-check="${s.dataset.select}"]`);
+ if (check) check.checked = item.checked;
+ })
+ );
+
+ const selected = scanItems.filter((it) => it.checked && it.request_id).length;
+ $("#import-pager").hidden = false;
+ $("#import-page-info").textContent =
+ `Seite ${importPage + 1}/${pages} · ${scanItems.length} Einträge · ${selected} ausgewählt`;
+ $("#import-prev").disabled = importPage === 0;
+ $("#import-next").disabled = importPage >= pages - 1;
}
+$("#import-prev").addEventListener("click", () => { importPage--; renderImportTable(); });
+$("#import-next").addEventListener("click", () => { importPage++; renderImportTable(); });
+
// ---- quick request from a scanned file ----
let quickItemIndex = null;
@@ -381,32 +424,21 @@ async function pickQuickResult(r) {
}),
});
missingReqs.push(req);
- // add the new request to every dropdown of the same media type, then link this row
- const item = scanItems[i];
- scanItems.forEach((it, j) => {
- if (it.media_type !== item.media_type) return;
- const sel = document.querySelector(`[data-select="${j}"]`);
- const opt = document.createElement("option");
- opt.value = req.id;
- opt.textContent = `${req.title} — ${req.authors} (${req.library_name})`;
- sel.appendChild(opt);
- });
- document.querySelector(`[data-select="${i}"]`).value = req.id;
- document.querySelector(`[data-check="${i}"]`).checked = true;
+ scanItems[i].request_id = req.id;
+ scanItems[i].checked = true;
+ renderImportTable();
$("#quick-dialog").close();
toast(`„${req.title}" angefragt und verbunden`);
} catch (err) { toast(err.message, true); }
}
$("#import-btn").addEventListener("click", async () => {
- const items = [];
- scanItems.forEach((item, i) => {
- const checked = document.querySelector(`[data-check="${i}"]`).checked;
- const reqId = document.querySelector(`[data-select="${i}"]`).value;
- if (checked && reqId) {
- items.push({ path: item.path, is_dir: item.is_dir, files: item.files, request_id: parseInt(reqId) });
- }
- });
+ const items = scanItems
+ .filter((item) => item.checked && item.request_id)
+ .map((item) => ({
+ path: item.path, is_dir: item.is_dir, files: item.files,
+ request_id: item.request_id,
+ }));
if (!items.length) { toast("Nichts ausgewählt", true); return; }
try {
const res = await api("/api/import", { method: "POST", body: JSON.stringify({ items }) });
diff --git a/static/index.html b/static/index.html
index 216288a..5714686 100644
--- a/static/index.html
+++ b/static/index.html
@@ -109,6 +109,11 @@
|
+