Line numbers are places in import and export; fix stale scripts
Import: each row's place is its line number, so blank lines leave a
place empty; a fully numbered text file ("38. Title") or a Rank column
gives places directly, and repeated numbers take the next free place.
Entries are added at those places (existing ones there move down), the
review shows each row's #, and the room check covers the highest place.
Export writes a blank line for every empty place, so line N is #N and a
file round-trips.
Static files now carry an ETag and unversioned ones are revalidated on
every load. Scripts import each other without a ?v= tag, so browsers kept
an hour-old import.js (with the "null" bug) after an update.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
88373176f2
commit
62fcf6b45d
7 files changed
+151
-72
No files matched your search
+14
-10
@@ -32,7 +32,7 @@ export function openImport({ list, cat, onListChange, onDone }) {
|
||||
dialogHead("Import a list", () => dlg),
|
||||
h("div", { class: "dialog-body stack" },
|
||||
h("p", { class: "muted" },
|
||||
`Entries are added after your last one, in the file's order. Use one title per line, or a CSV with columns like Title, Year, ${artistWord(cat)} and Note. `,
|
||||
`Line 1 becomes #1, line 38 becomes #38, and a blank line leaves its place empty${list.itemCount ? " (entries already at those places move down to make room)" : ""}. Use one title per line, or a CSV with columns like Title, Year, ${artistWord(cat)} and Note. `,
|
||||
"Each one is looked up and matched for you; anything Canon isn't sure about is left for you to check."),
|
||||
drop,
|
||||
text,
|
||||
@@ -117,14 +117,18 @@ export function openImport({ list, cat, onListChange, onDone }) {
|
||||
].filter(Boolean);
|
||||
summary.textContent = parts.join(" · ");
|
||||
|
||||
const n = chosen().length;
|
||||
const free = list.maxItems - list.itemCount;
|
||||
go.disabled = matching || n === 0 || n > free;
|
||||
const picked = chosen();
|
||||
const n = picked.length;
|
||||
const lastPlace = Math.max(0, ...picked.map((e) => e.row.place));
|
||||
const fits = list.itemCount + n <= list.maxItems && lastPlace <= list.maxItems;
|
||||
go.disabled = matching || n === 0 || !fits;
|
||||
go.textContent = matching ? "Matching…" : `Import ${fmt.format(n)} ${n === 1 ? "entry" : "entries"}`;
|
||||
room.hidden = matching || n <= free;
|
||||
room.hidden = matching || n === 0 || fits;
|
||||
if (!room.hidden) {
|
||||
const want = Math.min(list.itemCount + n, 65535);
|
||||
room.replaceChildren(icon("info"), `This list has room for ${fmt.format(free)} more. `,
|
||||
const want = Math.min(Math.max(list.itemCount + n, lastPlace), 65535);
|
||||
room.replaceChildren(icon("info"), lastPlace > list.maxItems
|
||||
? `The file goes up to #${fmt.format(lastPlace)}, but this list ends at #${fmt.format(list.maxItems)}. `
|
||||
: `This list has room for ${fmt.format(list.maxItems - list.itemCount)} more. `,
|
||||
h("button", {
|
||||
type: "button", class: "btn btn--sm", onclick: async (e) => {
|
||||
busy(e.currentTarget, true);
|
||||
@@ -163,7 +167,7 @@ export function openImport({ list, cat, onListChange, onDone }) {
|
||||
|
||||
const li = h("li", { class: `import-row is-${e.state}`, "data-i": e.i },
|
||||
h("div", { class: "import-row-head" },
|
||||
h("span", { class: "import-num" }, `${e.i + 1}.`),
|
||||
h("span", { class: "import-num" }, `#${row.place}`),
|
||||
h("div", { class: "import-src" }, h("b", {}, row.title), asWritten && h("span", { class: "muted small" }, ` ${asWritten}`)),
|
||||
badge),
|
||||
);
|
||||
@@ -299,9 +303,9 @@ export function openImport({ list, cat, onListChange, onDone }) {
|
||||
? {
|
||||
title: r.title, subtitle: r.subtitle, year: r.year, externalUrl: r.externalUrl, imageUrl: r.imageUrl,
|
||||
provider: r.provider, providerId: r.providerId, extra: { ...(r.extra || {}) }, description: r.overview || "",
|
||||
details: true, note: e.row.note || "",
|
||||
details: true, note: e.row.note || "", rank: e.row.place,
|
||||
}
|
||||
: { title: e.row.title, subtitle: e.row.subtitle || "", year: e.row.year || "", note: e.row.note || "", extra: {} };
|
||||
: { title: e.row.title, subtitle: e.row.subtitle || "", year: e.row.year || "", note: e.row.note || "", extra: {}, rank: e.row.place };
|
||||
try {
|
||||
const res = await api("POST", `/api/lists/${list.id}/items`, payload);
|
||||
added++;
|
||||
|
||||
Reference in new issue
Block a user